i may be falling into the trap of trying to make language x more like language y that i'm more familiar with, but i think that if a language has one or more nil values, it's usually worthwhile to draw a distinction between a variable that has one of those values and a variable that doesn't exist at all. lua gets some simplicity out of conflating these situations, because it means it doesn't need a separate mechanism for causing variables to cease to exist (you can simply assign nil), and sometimes it can simplify your code by leaving initialization implicit. but i think that the result is that lua is a lot more bug-prone
languages that do draw a distinction between not existing, and existing with a null value, include smalltalk, ruby, c, c++, python, javascript, perl, python, tcl, java, the bourne shell (except perhaps very early versions), pascal, common lisp, scheme, golang, rust, octave, and most assembly languages. conflating the two is not completely unique to lua; awk, basic, and arguably fortran 77 do that, though the nil value they give previously nonexistent variables is a numeric 0 rather than Γ
the bourne shell and by default perl also allow reads from nonexistent variables with well-defined semantics, and perl and js also allow reads from nonexistent table slots (hash and array slots) with well-defined but sometimes startling semantics. but none of these have the behavior shared by lua, awk, basic, and arguably fortran 77, where there's no way to tell the difference between a nonexistent variable and a variable that has had the null value assigned to it
so i think that lua's design choice here should be regarded as an experimental innovation, like java's checked exceptions; and, specifically, a failed one
so there would be no problem with pattern matching returning nil and storing it in a variable
I think having a special datatype differing between nil and null would still render the code the same, instead of using if var==nil, you're just now doing if var==null, if you're using a variable after you know a function was used and its nil you know it returned null. you can always just use { or false } if you really need to differ between nil (and waste space), that or use assert()
Also my problem with pattern matching returning nil is it breaks usage of concatenative :, as in match:""match"":match""
So if you use concatenative objects with :, make sure you never return any other type but the object itself. its what allows lpeg operator overloading to not error out in the middle of it.
what do you mean about pattern matching