I want to share some thoughts and ideas about a patch I am currently trying to write.
For now the only reason to use the colon operator is to write less (syntactic sugar) and to reuse the second last field:
very.deep.table.hierarchy:function()
->
very.deep.table.hierarchy.function(very.deep.table.hierarchy)
were "very.deep.table.hierarchy" is only evaluated once.
This is OK, but I don't think it's very fancy.
My patch idea is to make the colon operator more usable by simply allowing it in more places/cases.
The first change is simple and I have already a patch for it, I can release it as single patch if someone is interested.
This change simply makes the function call brackets optional if there is no argument, other than self which is implicitly added.
This means you can write:
require "string"
local text = "I can shout!"
print(text:upper) --> I CAN SHOUT!
I think this change is quite useful for the following reasons:
- No ambiguity: The : operator outside a function declaration like "function table:funct() ... end" already defines a function call, no need to define it twice with empty brackets.
- Backward compatibility: text:upper is so far no valid syntax, so allowing it doesn't break any existing code.
- Arguably better readability: print(text:upper) looks simpler than print(text:upper())
The idea is, to use this syntax for type conversion methods as well. The name would be the "type" of the returned value:
local myDouble = 1.0
local myInt = myDouble : integer -- equals myDouble // 1
local myString = myDouble : string -- equals tostring(myDouble)
The nice thing about this syntax is that it looks very similar to type definitions in UML notation.
This is actually the reason why I got the idea in the first place. This can also be used for implicit type conversation to userdata types:
local myDouble = 1.6
local myString = "I SAID, I CAN SHOUT!"
MyFunction(myDouble : fixedPoint, myString : stringBuffer)
MyFunction expects a fixedPoint userdata and a stringBuffer userdata argument.
Now I can also write this directly as:
MyFunction((1.6) : fixedPoint, ("I SAID I CAN SHOUT!") : stringBuffer)
But that's again not very nice, what I really want to write is:
MyFunction(1.6 : fixedPoint, "I SAID I CAN SHOUT!" : stringBuffer)
This might be just my personal opinion, but I think this is a very clean and readable way to define custom (userdata) types on the fly if they are needed.
I am well aware that I can also write:
MyFunction(fixedPoint(1.6), stringBuffer("I SAID I CAN SHOUT!"))
I just don't like that so much, maybe it's just the brackets all over the place that I dislike.
Anyway, with the first step already done I am now trying to handle the "hello":function and 1.6:function to work.
I am not sure how much I want to allow. Especially in this case:
print( lower "I'm getting loud with you !" : upper)
What should happen? Synstax error, print "I'M GETTING LOUD WITH YOU!", or "i'm getting loud with you!"?
Currently I think in this case, syntax error is the right thing, as it is not obvious in which order "lower" and "upper" are called.
It may be interesting to actually make the colon operator of higher order than the string call, that would allow one to write:
print "%e, %E" : format(math.pi, math.pi)
But I think this would take things too far.
If anyone has some more ideas or inputs on this style of syntax, I am open to listen and maybe I will be able to include it into my patch.
So far I am not even sure if I will be able to implement all changes I thought up myself :-)
--
Thomas