Skip to content
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

String after implicit object #618

Closed
ghost opened this issue Aug 16, 2010 · 26 comments · Fixed by #1061
Closed

String after implicit object #618

ghost opened this issue Aug 16, 2010 · 26 comments · Fixed by #1061

Comments

@ghost
Copy link

ghost commented Aug 16, 2010

Shouldn't this:

Hm.label(for: 'username', 'Username')

get compiled into:

      Hm.label({
        "for": 'username'
        },
        'Username'
      );

instead of:

      Hm.label({
        "for": 'username',
        'Username': 'Username'
      });

??

@hen-x
Copy link

hen-x commented Aug 16, 2010

Perhaps it would be a good idea if compact literal expansions (like {a, b, c}{a:a, b:b, c:c}) only worked inside of explicit braces, and not inside of implicit object literals. Otherwise, there is no way to "break out" of an implicit literal on a single line; individual values in an argument list, like in this example, will just be interpreted as keys.

@TrevorBurnham
Copy link
Collaborator

Actually, while this is baffling behavior at first glance, I think it's OK.

Consider that in Ruby, implicit hashes are allowed only for the last argument precisely because humans would have a hard time seeing that y is the third argument in the function call

foo(x, :a => b, :c => d, y)

So, if you use a hash as an earlier argument, you need to use curly braces. It seems wise to me, as a stylistic matter, to use curly braces for a hash that isn't the last argument to a function. Given the stylistic convention, scenarios like the above would be unlikely for two reasons: First, the caller would use curly braces around the hash; and second, the person who wrote the function would have made the hash the second argument rather than the first.

Also consider syntax highlighting. If for: 'username', 'Username' were all in the "hash" color, or if for: and 'Username' were both in the "key" color, a programmer trying to pass 'Username' as an argument would immediately realize their mistake and add curly braces.

So, I don't strenuously object to sethaurus' proposal, but I don't think it's necessary, either.

@ghost
Copy link
Author

ghost commented Aug 17, 2010

TrevorBurnham: That makes sense. Thank you.

@jashkenas
Copy link
Owner

Thanks for reporting this ... it's not too hard of a fix -- just one more check to make, while searching for the end of the implicit object. Here's the patch:

https://github.com/jashkenas/coffee-script/commit/474c372b17cd6ebd5eb6c26ef7f6cb5769c881bf

Closing the ticket.

@ghost
Copy link
Author

ghost commented Aug 17, 2010

Cool. Thank you, jashkenas!

@jashkenas
Copy link
Owner

Sorry, devtime, had to revert this commit for the following reason:

https://github.com/jashkenas/coffee-script/issues/#issue/631

@ghost
Copy link
Author

ghost commented Aug 19, 2010

Ok, jashkenas. No biggie. Thanks for letting me know.

@satyr
Copy link
Collaborator

satyr commented Aug 31, 2010

To prevent this, how about making object shorthand syntax a little more explicit:
{:a, :b} # {a:a, b:b}
Then we can omit braces in these cases as well:
f :k1, :k2, o # f({k1:k1, k2:k2}, o)
:puts = require 'sys' # {puts:puts} = require('sys')

@ghost
Copy link
Author

ghost commented Aug 31, 2010

satyr: I like it!

jashkenas: will you consider reopening this issue? or should we create a new one for satyr's proposal? Thanks.

@michaelficarra
Copy link
Collaborator

I like it as well. Nice suggestion.

@danielribeiro
Copy link

I like the way it is now. TrevorBurnham's comment on how ruby does it, also applying for pythons **kwargs, is tried and true, and makes perfect sense.

To solve it, you can already be expicit:
Hm.label({for: 'username'}, 'Username')
Compiles to:
Hm.label({
"for": 'username'
}, 'Username');
As expected. You can even leave out the parenthesis:
Hm.label {for: 'username'}, 'Username'

@StanAngeloff
Copy link
Contributor

I like satyr's proposal. How often would you really want to do fn key: value, 'key2' ? What's the point of having a string key with the same string value?

On a side note, why is fn key: value, a + b not valid but fn key: value, (a + b) is compiling. There is too much magic happening around implicit objects.

@ghost
Copy link
Author

ghost commented Sep 15, 2010

How often would you really want to do fn key: value, 'key2' ?

StanAngeloff: I agree with you -- it's much more common for me to need a string after a hash than needing a "string key with the same string value".

@ghost
Copy link
Author

ghost commented Sep 15, 2010

func(xx: zz, 'yy')

Also, the current behavior is counterintuitive. Most developers who'll come by the sort of code above for the first time will think that the second parameter is a string.

@danielribeiro
Copy link

If it can be done, wtihout requring explicit brackets great.

@jashkenas
Copy link
Owner

I spent a long time trying to solve this last night, and got mostly nowhere. If anyone has some brilliant ideas for parsing it, I'd love to hear them. This is the crux of the issue.

call key: val, arg

call key: val, key2: call2 arg1, arg2, arg3

In a perfect world would compile into (I think):

call({key: val}, arg);

call({key: val, key2: call2(arg1, arg2, arg3)});

The trick is that when we're rewriting the token stream and inserting implicit parentheses and braces, the braces go first. I can't think of a rule that would correctly distinguish the two parses above, and would know that the implicit braces are supposed to end early for the first bit of code. Something where the brace and paren rules mutually invoke each other might do the trick...

@danielribeiro
Copy link

It can get a bit harder: multiple inline objects. Like:
call key: val, key2: call2 arg1, okey: oval, okey2: oval2, notakeyorarg
Being compiled into:
call({key: val, key2: call2(arg1, {okey: oval, okey2: oval2}, notakeyorarg)});

@jashkenas
Copy link
Owner

I haven't found a way to make this case parsable, in general. I'm afraid we'll have to accept it as a known limitation of implicit objects (which, for the record, are still more flexible than in Ruby, for example).

Closing this ticket as frozen for the time being, and if someone comes up with a fix, it'll be warmly welcomed.

@jashkenas
Copy link
Owner

A patch to fix this issue is now on master, which now compiles the original test case for this issue correctly. If you have a minute to give master a try, and see if it's working for your use cases, please do.

#1061

@ghost
Copy link
Author

ghost commented Jan 19, 2011

jashkenas,

Wow! This is good news! I'll be trying this out later today. I'm afraid I haven't been keeping up with the commits lately -- Is the current code on master as stable (or more) as 1.0 by now? Would you say it's pretty safe to start compiling my code with it? Or should I be using some branch?

@jashkenas
Copy link
Owner

master is the future 1.1 ... 1.0-stable is the future 1.0.1 -- this particular commit is on master, because it's highly likely that it's not fully baked yet. That's why I'm asking you to kick the tires a bit ;)

@ghost
Copy link
Author

ghost commented Jan 19, 2011

Sure. Will do. :)

@satyr
Copy link
Collaborator

satyr commented Jan 19, 2011

#1061

Some observations:

  • f a:b, c is valid, but [a:b, c] isn't.
  • f a:b, c+1 still doesn't work.
  • f a:b, g c still doesn't work.

@dohse
Copy link

dohse commented Jan 19, 2011

yep the fix is just a hack to prevent unexpected results.
all three cases result at least in an error message.

@TrevorBurnham
Copy link
Collaborator

Those are serious failures, though. Is the hack more generalizable?

@jashkenas
Copy link
Owner

Looks like the discussion is happening on #1061 ... let's keep it over there.

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants