leafo / moonscript

:crescent_moon: A language that compiles to Lua
https://moonscript.org
3.2k stars 192 forks source link

'\' is weird syntax why not keep ':' and '='? #35

Closed nightsailer closed 11 years ago

nightsailer commented 12 years ago

I know MoonScript replace ':' with '\' to call an instance method, but I think it's sooooooo weird. As most language, '\' meant escape. So, try to read: file\read vs file.read vs file:read

When reading code, I think the first way is hardest.

and try these code:

obj1\method2 "\01\002\010\"

And, I don't think so use ':' to assigning a value to key in a table is better than '='.

So, why not keep ':' and '=' behavior?
It's bad idea to change the operator behavior, it make hard to port code between Lua and Moonscript, also make people more confused.

leafo commented 12 years ago

It's not apparent at first, but using a dedicated character for building hash tables, : let's you do some interesting things with syntax:

I can write open hash tables, tables that aren't bounded by { and }:

x = hello: world
y = some: "value", another: 2323

my_func 1, 2, 3, opt1: "value", opt2: "value2"

This already makes the syntax look a lot cleaner when writing small tables. In the last example we've essentially written named arguments thanks to the syntax (Think of Ruby). Imagine if I were using =, the first example would be x = hello = world. That syntax is too ambiguous with assignment to derive a table out of it.

I can also use the dedicated : operator in other places now too. Here I used it as a prefix operator to quickly assign both the key and the value:

hello, world = 100, "xxx"
z = :hello, :world

-- This is shorthand for:
--
-- z = { hello: hello, world: world }

And because I am using : for building tables, I couldn't use it for calling methods on tables like in Lua because of similar syntactic ambiguity issues like mentioned above.

I experimented in with a few options, both 1 and 2 character ones, but I decided that for such a common operator it should be 1 character. I settled on \. I admit it felt strange at first, but after using it for a while now, it's feels as just natural as any other character.

Having a unique character for the method invocation also lets us do some interesting things with the syntax.

For example, when you use the backslash but don't pass in any arguments, it creates a new function that is bound to the receiving object which calls the named method. I call these function stubs.

Here's an example:

-- a simple object with 1 method
counter_obj =
    count: 0
    increment: =>
        @count += 1
        print "The count is", @count

counter_obj\increment! -- prints "The count is 1"

-- notice here how we use \ but don't pass any arguments
bound_method = counter_obj\increment

bound_method! -- "The count is 2"

print counter_obj.count -- prints 2

I also enable the use of \ as a prefix operator for the import statement. It does the same thing as above, creates a bound function for the table that is being imported from.

There's even one more MoonScript construct that's only possible if I use unique operators, check out how the with statement works.

So that's why I use backslash. Write some MoonScript and you'll find that it fits perfectly.

nightsailer commented 12 years ago

@leafo I agree with some of your decisions, but, I still prefer ':' instead of '\' ;-) maybe use '=>' to build table also good, like Perl, Ruby ? but, fat arrow also used to send self as first augment, should use '->' in class definition default? every method in class body should receive self as first augment? like,

class a method1: ()->

just compiled to:

a:method1() {}

But, ok,ok, it's just my feel, maybe it's not a big deal really.

As your said, it's felt strange at first, I should try it again.

zah commented 12 years ago

Is there a problem if the meanings of \ and . are reversed?

obj.merhod foo, bar will become method invocation and table\insert t, value will become the classic lua function-from-namespace call.

Obviously, this goes agains the established lua practices and the standard library, but I think Moonscript should promote the OOP style introduced in lua 5.1 (e.g. str:gsub). Also, in good lua code, table lookups are often cached into local variables anyway:

{ insert, sort } = table

for i = 1, 10
   insert t, i

foo.bar will still be a regular field access just like in coffeescript. foo.bar! is the method call without arguments. and foo\bar could be the function stub. "with" statements could be handled with the default in-object syntax:

with Foo
   @foo bar
   print @baz
   @gaz!   

The other benefit is that this will lead us to far more "polyglot code" - i.e. class libraries that run with little or no modifications on both coffeescript and moonscript.

Coffeescript is rapidly gaining node.js web development libraries like TowerJS that in theory could be easily ported to run on top of moonscript/luvit. People will be attracted to LuaJIT's performance and this would be good news for Moonscript.

I know, you've already developed quite a lot of libraries in Moonscript, but the language is still young and now is the time to make such breaking changes (nothing a few replace in files tricks cannot fix).

leafo commented 11 years ago

Closing this. Sticking with \.

mattaylor commented 11 years ago

+1 for everything that zah said. . Is so much more natural for method invocation and is immediately accessible to anyone coming from the coffeescript / javascript / perl / python / java / groovy / ruby world.
\ really is a weird language turn off.

pwhelan commented 10 years ago

this is a real serious downer. Thanks @devast8a for the fork.

stevedonovan commented 10 years ago

I must say I've always found \ to be ugly - can't help feeling it's the escape character. And '=' for table key-pairs always felt comfortable in Lua.

nilnor commented 10 years ago

I have to say I agree - it's been close to two years of developing in Moonscript and I dislike the \ operator as much now as I did in the beginning. It does not feel natural, and is for me the biggest drawback to Moonscript. I really wish this would be revisited.

Maybe I'm missing something, but would it not be enough to require whitespace after the colon for it to be considered a table key? So obj:method is a method invocation, while key: value is a table key?

pwhelan commented 10 years ago

would it be a terrible sin to allow '->' as an extra and alternative syntax for instance method invocations?

stevedonovan commented 10 years ago

On Mon, Apr 7, 2014 at 6:50 AM, Phillip Whelan notifications@github.comwrote: would it be a terrible sin to allow '->' as an extra and alternative syntax for instance method invocations?

It would be familiar, although a little C-ish. As an alternative, yes. I like Nil's idea of using a little whitespace for ':' as key/value, but I imagine there's already a lot of Moonscript out there ;)

stevedonovan commented 10 years ago

On second thoughts, scratch that: "->" means "function" and it would be terribly confusing if it meant something else in a different context.

etandel commented 10 years ago

More than confusing, -> is actually ambiguous.

a = (b)->c!

could mean either of the following:

local a = function(b) return c() end

local a = (b):c()
etandel commented 10 years ago

I think \ is just fine. Sure, it is a bit quirky, ugly and feels... 'dirty', but it's easy to type and easy to read / mentally parse.

However, if change is inevitable, here are my suggestions, ordered from what I believe is most reasonable to least reasonable:

a::b::c!

The double collon, the good old Paamayim Nekudotayim. Pros:

Cons:

a<-b<-c!

Pros:

Cons:

a$b$c!

Pros:

Cons:

a>>b>>c!

Pros:

Cons:

a~b~c!

Pros:

Cons:

PS: I am seriously allergic to PHP; my physician says it may actually be fatal.

stevedonovan commented 10 years ago

Of these alternatives, I'd say that the double-colon reads best... and it's easy to type.

stevedonovan commented 10 years ago

Except years of doing C++ makes me think that :: means a static function, not a method. So Richard Hundt's shine has :: for that purpose, and '.' meaning a method call. No easy answer!

nilnor commented 10 years ago

It would be good to know if changing/supplementing this is something that would actually be considered at all, or if it's set in stone now. What's the verdict @leafo? :)

ludamad commented 10 years ago

I must comment that this is a very large issue with Moonscript readability as an experienced Lua user. '!' would have been a better choice than '\', IMO.

Edit: On a more constructive note, adding this to ~/.vim/after/syntax/moon.vim increased readability for me when using the VIM moonscript plugin. It makes \ appear as :, except on the currently selected line.

~/.vim/after/syntax/moon.vim:

if !has('conceal')
    finish
endif

syntax match moonOp "\\" conceal cchar=:

hi! link Conceal Operator
setlocal conceallevel=2
adderlan commented 9 years ago

It troubles me that this single character is even an issue. Sure, it would be nice to have a richer set of symbols available, but one has to choose from the very limited set that's available on standard keyboards to even hope of getting any traction (which I hope changes at some point, because symbols are important). So as long as the meaning is clear, I won't get too hung up on the aesthetics.

What troubles me more however is that some people have suggested replacing it with ':' and then consider whitespace to decide its meaning. '\' may be ugly, but its meaning is very obvious, and doesn't change when you indent/nest code. On the other hand, using ':' in the way @nilnor and @tbastos suggest makes its meaning far less obvious, and changes it when you indent/nest code. So for nothing more than an aesthetic consideration people seem willing to limit the expressiveness/formatting of a language, make code more difficult to read, and raise the probability of generating hard to spot errors. Significant whitespace should be used to make code more readable, not less.

And this really, really bugs me, because if this is the sort of thing programmers are getting hung up on and driving their decisions, I'm gravely concerned for the future. Forget 'should', programmers need to be pragmatic. It's fundamental to the discipline. And while engineering always involves tradeoffs (for example, using symbols not included on a keyboard may increase clarity but decrease accessibility), this is not an example of such.

So good choice @leafo, and good luck with MoonScript.

tbastos commented 9 years ago

@adderlan MoonScript is already whitespace sensitive in a few places, in case you haven't noticed. But you're right, in retrospect my comment about pragmatism is off. I think there are pragmatic reasons why MoonScript should have kept ':' for method calling, namely the "barrier of entry" and code legibility for new users coming from vanilla Lua. This was my criteria when evaluating MoonScript a while back: can people who know Lua (and e.g. CoffeeScript) be expected to read MoonScript without many "wtfs"? The answer is probably yes, but what troubles me is that some "wtfs" could have been avoided. But I don't want to contribute to the polemic so I'll delete my suggestion. Peace :)

nilnor commented 9 years ago

@adderlan I think that reducing it solely to a question about "aesthetics" is vastly over-simplifying it. People consider it "ugly", but I doubt that has much to do with the graphical appearance of the \ character itself. Rather I believe it's a cognitive mismatch for most people, since most mainstream languages use the \ operator for escape sequences and that makes it jarring.

As for it being a pragmatic choice, you could argue in both directions. Yes, there's a shortage of usable symbols, making it a pragmatic choice. And yes, the backslash is for a lot of people typically associated with different semantics, making it in my view a non-pragmatic decision. At the end of the day, many people consider it off-putting and it makes them less likely to consider Moonscript. It's been an issue for me, and as I've advocated the use of Moonscript to other people I've consistently gotten the same reaction - "looks nice, but the backslash thing? eew". It's a barrier to adoption, and recognizing this seems pragmatic to me.

Talking about keyboards, I've seen the "easy to type" argument being brought up a couple of times, While perhaps tangential to the larger issue, I just wanted to point out that it's highly dependent on the keyboard layout. I'm Swedish, and while the backslash is available on Swedish keyboard layouts, it's accessible through the RSI-inducing alt gr + \ combination, both keys being located on the right hand side of the keyboard which makes it very uncomfortable to write. I personally use the US layout while coding, but as far as I can tell most people don't.

As for the proposal to change the meaning of : depending on whitespace, I recognize that it would limit the language somewhat in that it would not possible to for instance put the actual method after a new line. I don't see the whitespace sensitivity as an issue; as @tbastos pointed out Moonscript is already sensitive to whitespace. It wouldn't make the language harder to read for me, but that's a subjective issue. As for generating "hard to spot errors", that strikes me more as a theoretical issue than a practical one, but I'm interested to see examples where this would be a real issue.

stevedonovan commented 9 years ago

On Fri, Feb 13, 2015 at 9:04 AM, Nils Nordman notifications@github.com wrote:

language harder to read for me, but that's a subjective issue. As for generating "hard to spot errors", that strikes me more as a theoretical issue than a practical one, but I'm interested to see examples where this would be a real issue.

Well, here would be an example

t = {key1: value1, key2:value2}

If colon is overloaded, then there are two very distinct meanings here; the second is a partially-applied method bound to key2, the first is an actual key/value pair. Here the flexibility of tables bites us, because it is possible for this to compile correctly, and yet yield puzzling results!

So I think (on further thought) to learn to live with backslash - aesthetics are relative, as has been pointed out.

The alternate way of doing this is to just use '=' in table constructors ;) Not sure what the syntactical implications are.

devast8a commented 9 years ago

If colon is overloaded, then there are two very distinct meanings here; the second is a partially-applied method bound to key2, the first is an actual key/value pair. As far as the parser is concerned it's easy to give method binding and method application two different symbols.

For example, you could keep \ for binding and have : only for method application. You still have a similar problem though

t = {key1: func1!, key2:func2!}

The alternate way of doing this is to just use '=' in table constructors ;) Not sure what the syntactical implications are. Well assignment isn't an expression, so you could... But I'd much rather leave '=' open for assignment as an expression.

On Fri, Feb 13, 2015 at 5:47 PM, Steve J Donovan notifications@github.com wrote:

On Fri, Feb 13, 2015 at 9:04 AM, Nils Nordman notifications@github.com wrote:

language harder to read for me, but that's a subjective issue. As for generating "hard to spot errors", that strikes me more as a theoretical issue than a practical one, but I'm interested to see examples where this would be a real issue.

Well, here would be an example

t = {key1: value1, key2:value2}

If colon is overloaded, then there are two very distinct meanings here; the second is a partially-applied method bound to key2, the first is an actual key/value pair. Here the flexibility of tables bites us, because it is possible for this to compile correctly, and yet yield puzzling results!

So I think (on further thought) to learn to live with backslash - aesthetics are relative, as has been pointed out.

The alternate way of doing this is to just use '=' in table constructors ;) Not sure what the syntactical implications are.

— Reply to this email directly or view it on GitHub https://github.com/leafo/moonscript/issues/35#issuecomment-74214455.

nilnor commented 9 years ago

On 02/13/2015 08:17 AM, Steve J Donovan wrote:

Well, here would be an example

t = {key1: value1, key2:value2}

Sure, that's the resulting semantic difference. But this strikes me as most often falling in the same general category as typos, etc. - might be hard to discover when reading the code, but will be readily apparent when actually executing the code. It's a bigger problem only if key2:value2 is a valid method binding, but presumably that case is not so common as to be a real issue.

stevedonovan commented 9 years ago

On Fri, Feb 13, 2015 at 9:43 AM, Nils Nordman notifications@github.com wrote:

be hard to discover when reading the code, but will be readily apparent when actually executing the code.

I find with dynamic languages that code needs to be clear and obvious, since as humans we rely on static analysis. It also takes some training to 'see' the difference between ':' and ': '. Of course, we have Tests, but it saves time to catch things before running programs. At least \ is very obvious.

It's a bigger problem only if key2:value2 is a valid method invocation, but presumably that case is not so common as to be a real issue.

It is a valid idiom in MS (unlike Lua) and binds the first argument of the method to the object resulting in a function. Most useful when providing callbacks!

My question rather is why stick with colon for table constructors? Just so that MS looks like everyone else?

nilnor commented 9 years ago

It is a valid idiom in MS (unlike Lua) and binds the first argument of the method to the object resulting in a function. Most useful when providing callbacks!

Yes, I misread there, and I'm aware of what bindings are. Still, my points is that for most cases this would fail very visible at runtime, provided that key2 is not a valid table.

My question rather is why stick with colon for table constructors? Just so that MS looks like everyone else?

Now we're really talking about major changes :)

That would have avoided some disambiquity. On the other hand, the short table syntax wouldn't work anymore, e.g. key: foo currently evaluates as a table, whereas one typically wouldn't expect key = foo to evaluate as a table at all. And if it did that would look weird, e.g. my_func bar = foo :)

stevedonovan commented 9 years ago

On Fri, Feb 13, 2015 at 10:12 AM, Nils Nordman notifications@github.com wrote:

That would have avoided some disambiquity. On the other hand, the short table syntax wouldn't work anymore, e.g. key: foo currently evaluates as a table, whereas one typically wouldn't expect key = foo to evaluate as a table at all. And if it did that would look weird, e.g. my_func bar = foo :)

Ah, and it's such a nice finger-friendly syntax that! Language design is hard, I can live with \

hems commented 9 years ago

could we just use the classic "." and fix the other things instead of messing with Mr. Classic Dot ?

devast8a commented 9 years ago

Well . already means something else, you'd have to change it first.

ludamad commented 9 years ago

I like Moonscript very much and I consider it a nicer interface to LuaJIT. I think it's a bit sad that Moonscript wasn't more conservative in its changes in a sense, though. (Coffescript compatibility was stressed but feels weird very often to me). As it stands it is not a satisfying answer to "I like Lua, but I want a bit more syntactic sugar". I find myself avoiding Moonscript features that would make my code look alien to Lua programmers. Overall, I think from the strong thoughts on this topic that there is room in the niche space for a more conservative Lua-sugar language, but there is nothing objectively wrong with Moonscript's choices.

hems commented 9 years ago

indeed, there is nothing wrong with making it's own choices, and i love this idea.

but messing with Mr. Dot felt very weird to me and as @ludamad will look very alien, not only to lua programmers, but to any other programmer that might end up having to deal with the code without previously having some "training", which is very doable with other languages like coffee script ( as long as you don't cut a lot of corners in 1 line ).

codic12 commented 4 years ago

i'd say :: is a decent alternative