lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Lua's usual fix for switch statements is to use tables. This is fine,
but it doesn't respect metatable __eq() and it leaves us wanting when
a more complicated kind of matching is necessary. Unfortunately match
syntax tends to be pretty complicated, which isn't really "the Lua
way". But if you've seen how Haskell lets you special-case a function
at a specific value, you know it looks nice.

Here's a simple and very powerful way to do pattern matching in
variadic functions:

function do_something(foo, ...)
      _1, _2, _3 = ...
      va_case(1, ...) do   --matches 1 followed by anything
            -- some code here
            break
      va_case(_1, "bar") do   -- matches any object, followed by bar, alone
            -- some more code here
      va_case(_1, "bar", "no-baz") do   -- no break, falls through like C
            -- some more code here
            break
      va_case(...)   -- default, matches anything
            -- code etc
      end
      -- some other code
      isnum = {}
      setmetatable(isnum, {__eq = function(self, other) return
type(other) == "number" end})
      va_case(isnum, ...) -- matches when the first argument is a number
            -- va_case can be used anywhere but always matches the vararg
      end
end

Just as in a loop, the break keyword takes you to the end statement
corresponding to the current do block. Multiple va_case statements can
be chained together like elseif, but fallthrough happens like a C
switch statement. The metamethod __eq is available and treats the
va_case argument as being on the left. Ideally, local variables should
carry over too, but implementation limitations may prevent that.
Semantically, Lua doesn't have to worry about trying to access a local
variable defined in a line you skipped because it just substitutes
nil.

Compared to traditional pattern matching, I think va_case is much more
"Lua". It uses only one keyword to implement a lot of features -- you
can match multiple items, you have optional case fallthrough, and you
can use metatables to match things like types and subfields without
having to use any special pattern syntax. There is no need to specify
a match argument, and because va_case is limited to a particular
function, it does not encourage abuse. This is consistent with the Lua
philosophy of including a small number of flexible features that can
be used together to build high-level constructs, and preserves
readability. Plus, va_case is not likely to be a common variable name,
so there is not much to worry about using it as a keyword.

Anyway, I know the mailing list gets like thirty suggestions per day
so I hope this has been one of the better ones.