-
Notifications
You must be signed in to change notification settings - Fork 191
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
method invocation using .
#92
Comments
(Hm, maybe it would be better to continue discussion in the existing thread, not to create a new one..) Ah, backward compatibility is a good idea. I see no ambiguity with e.g. hash- |
I've already discussed this here: #35 (comment) Do you understand why Lua has both I describe in detail in the other issue why it's important to have two separate operators for method invocation, table property assignment and regular assignment. (Thus I don't use
Additionally, I'm not looking to encourage running CoffeeScript inside of MoonScript. They are too different to make it worth it, and in my opinion Lua got a lot of things right that are completely broken with JavaScript. If I'm spending my time trying to convert Lua into something that works like JavaScript then I've got it all wrong. |
I understand your arguments, however the compromise proposal from zah in #35 (comment) seems like a very elegent solution that could address your concerns whilst also providing a more accessible syntax. Apart from the fact that these woud be breaking, backwards incompatible changes, are there any other reasons why not to go down this route? |
Well, this and the very different underlying semantics of MS (Lua) and CS (JavaScript).
Having BTW, I have nothing against Also, backwards compatibility is a a big thing for such a trivial and subjective problem (which token looks nicer). |
I think the If you haven't already, the closures and objects are equivalent article on the C2 wiki is definitely worth a read. While a little disjointed (as such C2 articles always are), the point is clear and profound: having either closures or objects in a language, especially a dynamic one (whatever that really means), is enough to gain the benefits of both. This is because a closure, like an object, is a binding of (in Lua, mutable) data to runtime-determined behavior. With this, you get two of the major selling points for object-orientation: data hiding and polymorphism. The only caveat is that a closure can only specify one method, but this is trivially easy to solve by combining multiple closures into a table: new_account = ->
with {}
balance = 0
.get_balance = -> balance
.deposit = (amount)-> balance += amount
.withdraw = (amount)->
balance -= amount
assert balance >= 0, "You're broke!"
amount and there you have it: a full-featured object, complete with encapsulation (which is actually more than the standard This is relavant because, under this scheme, the convention of passing in a "self" argument (which is redundant and unsafe, actually, as a malicious user could potentially set "self" to anything they want) becomes a thing of the past, eliminating the need for a my_account = new_account!
my_account.deposit 100
buy_something_at_starbucks my_account.withdraw 5 Look ma, no If you want more python-like classes that still use pythonic_class = =>
result = self
instance_mt = {
__index: (key)=>
if 'function' == type result.methods[key]
(...)-> result[key] self, ...
else
result[key]
-- maybe add other metamethods whose
-- implementations delegate their computation
-- to instance-defined functions. For example: __add: (other)=> self.__add other
}
uninformative_error_message_if_the_client_is_trying_to_do_something_stupid = [[
Dangerous voodoo! If you're getting this error message, that probably wan't very informative, but that's ok: you know what you did. Stop messing with "self" and clean up any other code-smell like this!
]]
setmetatable self, {
__call: (...)=>
assert rawequal(self, result), uninformative_error_message_if_the_client_is_trying_to_do_something_stupid
instance = setmetatable {}, instance_mt
instance.__init ... -- in the spirit of python. Rename to "new" if you so please.
__index: (key)=>
assert rawequal(self, result), uninformative_error_message_if_the_client_is_trying_to_do_something_stupid
@parent and @parent[key]
} use it like this: Account = pythonic_class
__init: (@balance)=>
deposit: (amount)=> @balance += amount
withdraw: (amount)=>
@balance -= amount
assert @balance >= 0, "You're broke!"
amount
my_account = Account 100
buy_something_at_starbucks my_account.withdraw 5
-- note: since this is a close-emulation of python semantics, we also get the ability to directly modify fields
-- that is, there is no data hiding. Watch:
my_account.balance = "Where is your encapsulation god now?"
-- still, that's standard moonscript semantics, so you're probably already comfortable with it. the neat thing is that here, even though methods are closures, the implementation of those closures is subject to change: -- all the above code...
old_deposit = Account.deposit
Account.deposit = (amount)=>
-- check for sneaky negative amounts that could put you in debt without issuing the correct error message
assert amount >= 0
old_deposit self, amount This is much closer to the way that moonscript classes work. Really the only difference is that you can use your arguably more readable Although javascript and ruby both appear to work using the system outlined above as well, there are subtle distinctions: In Javascript and ruby, Important note: Be wary of the member-function-call syntax. This: @foo bar, baz compiles to this: self:foo(bar, baz) which will cause a subtle error if @.foo bar, baz instead. |
I'm with Leaf on this one - the two operators are distinct in Lua for a good reason (it's one of the reasons why Lua is so much more zippy than Python, which has to create this closure implicitly). \ is a bit ugly sure, but colon will not do, alas. Mr Simian shows us how one can explicitly construct objects that preserve '.' by making all these closures up front. Compatibility with the rest of the Lua ecosystem is important, because otherwise MS is a cool language without libraries ;) MS has a nice bit of sugar that |
Why not |
@SelectricSimian very helpfull discussion. Thanks, |
@fillest I want to allow line breaks after access operators: x = some_object\
a_method! If the |
@leafo After? Hm, it's better to place it before: x = obj
\some!
\method!
\chain! vs x = obj\
some!\
method!\
chain! But ah yes, it would really look like tables, ok sorry.. x = obj
:some!
:method!
:chain! |
@fillest It conflicts with the syntax of with something
\hello! |
I thought \ was really ugly when I started using it, but maybe that's just because it's so different from other languages. I think it's fine now, it's as good as any other character, and easy to type (no shift key) unlike : It looks a little like an arrow from the instance to the method. |
I agree. I think |
I know this issue has been discussed a couple of times before and closed, but Id really like to understand why the
.
operator could not be used to invoke method in additon to than the decidedly ugly\
(which apart from being ugly is also highly confusing when not used as an escape character.The exisitng
\
could still be retained for back- compatability, but it should also be possible to support.
notation as well. If the RHS is trailed with arguments,()
or!
then it should be easy to determine that this is method invocation rather than property access. I can't believe that there is much of a penalty for this kind of linguistic simplification, which is afterall one of the chief reasons for using a language like moonscript in the first place.This would not only improve code readability but it would also align so much better with many of the most popuar languages out there including java, python, javascript, ruby etc...
Which could help adoption. This is probably the single biggest barrier to cooffescript compatible moonscript and vice versa.
The text was updated successfully, but these errors were encountered: