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

Implicit objects and arrays as first function argument #50

Closed
ghost opened this issue Jun 21, 2012 · 25 comments
Closed

Implicit objects and arrays as first function argument #50

ghost opened this issue Jun 21, 2012 · 25 comments

Comments

@ghost
Copy link

ghost commented Jun 21, 2012

Why isn't it allowed to do:

someone
  name: "foo"
  age: 20
, callback

someone
  "foo"
  20
, callback

One of the selling point with LiveScript is that it removes the need for a closing character.

The only exception is:

someone {
  name: "foo"
  age: 20
}, callback

someone [
  "foo"
  20
], callback

This makes the code more verbose than the CoffeeScript version (the array syntax stays the same).

Can't we just remove the "pyramid effect" in all eternity just like Jade, Haml and Stylus have done but for HTML and CSS.

@adrusi
Copy link

adrusi commented Jun 21, 2012

for implicit objects or arrays as the first arguments, you need to use do:

someone do
  name: "foo"
  age: 20
, callback

someone do
  "foo"
  20
, callback

@ghost
Copy link
Author

ghost commented Jun 21, 2012

That doesn't work.

You can't have ", callback".

That will generate a compilation error.

Sent from my iPad

On 21 jun 2012, at 18:49, Adrian Sinclairreply@reply.github.com wrote:

for implicit objects or arrays as the first arguments, you need to use do:

someone do
 name: "foo"
 age: 20
, callback

someone do
 "foo"
 20
, callback

Reply to this email directly or view it on GitHub:
#50 (comment)

@ghost
Copy link
Author

ghost commented Jun 21, 2012

An example of what I dislike:

From this in CoffeeScript:

@add
  xtype: "textfield"
  itemId: "label-textfield"
  name: "filter"
  emptyText: "Filter on name"
  height: 30
  selectOnFocus: true
@on
  change: (field, newValue, oldValue) ->
    something!

To this in LiveScript:

@add {
  xtype: "textfield"
  itemId: "label-textfield"
  name: "filter"
  emptyText: "Filter on name"
  height: 30
  selectOnFocus: true
}
@on {
  change: (field, newValue, oldValue) ->
    something!
}

It feels like a major drawback.

I execute functions passing an implicit object everywhere throughout my app and it gives me a bloated feel.

@gkz
Copy link
Owner

gkz commented Jun 21, 2012

The following compile as you wish. Note that when calling against blocks starting with implicit objects/array you must start off with do

someone do
  name: "foo"
  age: 20
  callback

Notice the indentation - it needs to be correct. Also, you don't need the comma.

someone do
  * "foo"
    20
  callback

Notice the star to show that the first two items are a list, not seperate arguments.

@add do
  xtype: "textfield"
  itemId: "label-textfield"
  name: "filter"
  emptyText: "Filter on name"
  height: 30
  selectOnFocus: true

@on do
  change: (field, newValue, oldValue) ->
   something!

@gkz gkz closed this as completed Jun 21, 2012
@ghost
Copy link
Author

ghost commented Jun 21, 2012

Why does it force us to use do? Is it to create a new scope?

Also, the 2nd example with the array doesn't work. I have tried it in the compiler on the doc website but it compiles to arguments passed instead of an array.

Johnny

Sent from my iPad

On 21 jun 2012, at 22:59, George Zaharievreply@reply.github.com wrote:

The following compile as you wish. Note that when calling against blocks starting with implicit objects/array you must start off with do

someone do
name: "foo"
age: 20
callback

Notice the indentation - it needs to be correct. Also, you don't need the comma.

someone do
* "foo"
20
callback

Notice the star to show that the first two items are a list, not seperate arguments.

@add do
xtype: "textfield"
itemId: "label-textfield"
name: "filter"
emptyText: "Filter on name"
height: 30
selectOnFocus: true

@on do
change: (field, newValue, oldValue) ->
something!


Reply to this email directly or view it on GitHub:
#50 (comment)

@gkz
Copy link
Owner

gkz commented Jun 21, 2012

No new scope is created. Think of do in these cases as replacing parentheses.

add do
  2
  3

is the same as

add(
  2
  3
)

also

someone do
  * "foo"
    20
  callback

compiles for me to

someone(["foo", 20], callback);

Why is the use of do required? Well that was inherited from Coco, and knowing @satyr, he probably had a very good reason. Take a look at the section 'implicit call/object interaction' in https://github.com/satyr/coco/wiki/improvements

@vendethiel
Copy link
Contributor

Mostly because it forces to see an implicit call, where coffeescript would fail to read after the implicit object, I think. (but, yeah, @satyr obviously has reasons)

@satyr
Copy link
Contributor

satyr commented Jun 22, 2012

good reason

CoffeeScript's implicit call generally doesn't work against blocks, but has a specialcase for implicit objects:

# f({k: v}, x)
f
  k: v
  x

which causes problems:

# fails
f
  x
  k: v
# fails
r = switch
      when x
        k: v

Coco removed the specialcase and instead made do block work as multiline arguments.

@ghost
Copy link
Author

ghost commented Jun 22, 2012

What are the reasons for:

f 1,
  name: "foo"
  true

and not

f
  name: "foo"
  true

@ghost
Copy link
Author

ghost commented Jun 22, 2012

I guess it's not that big deal with do. But I think LiveScript should be targeting 0 compromises to create the perfect language.

  new Ext.util.KeyMap do
    target: Ext.getDoc()
    binding:
      * key: Ext.EventObject.L
        alt: yes
        defaultEventAction: "preventDefault"
        handler: -> app.sendEvent "changeListView"
      * key: Ext.EventObject.UP
        defaultEventAction: "preventDefault"
        handler: -> app.sendEvent "upKeyIsPressed"

Cons:

  1. It's ambiguous since do in other places actually creates a new scope in LiveScript (in CoffeeScript and in Ruby). Perhaps we wanna make a search for do to know where we are creating a new scope. Erase confusion!
  2. It doesn't sound right to read do all the time. It would be cleaner without it. Just like how we don't want to read function all the time, since our brain then read something that has nothing to do with the actual logic we wanna do. A symbol would be better in that case just like -> instead of function.
  3. In the above example we didn't need do after binding, it just doesn't feel consistent that we have to think to add do after functions, only if it's as the first arg. If it's after the first arg, it's ok to leave it out. That seems weird and it's add complexity in the design, something the user shouldn't think about at all!

Please reopen this issue.

@satyr
Copy link
Contributor

satyr commented Jun 22, 2012

What are the reasons for:

f 1,
  name: "foo"
  true

This is an unambiguous case. The 1 indicates the start of an implicit call, and , indicates the block after it is part of the arguments.

f
  name: "foo"
  true

This is ambiguous due to constructions like if. Consider:

if f
  name: "foo"
  true

do in other places actually creates a new scope in LiveScript

Incorrect.

@ghost
Copy link
Author

ghost commented Jun 22, 2012

The if statement was good to describe the problem. But could another word or a symbol perhaps be used?

do -> a = 2
a #=> a is not defined

Doesn't this mean it is creating a new scope?

@satyr
Copy link
Contributor

satyr commented Jun 22, 2012

That scope is from ->. do is just calling it. Observe:

$ coco -ps
  do
    a = 2
  a

2

@adrusi
Copy link

adrusi commented Jun 22, 2012

@satyr this is one of my problems with such syntactically stripped-down languages, often consistency is sacrificed for the sake of syntactic unambiguity, where I think the former is more important (obviously unambiguity is required for the compiler to work, but the syntax should not have so few landmarks that it happens often at all)

I mean the language is nice and all, and I plan to use it in the next project that I see fit, but I don't see the point of such a syntax with so few non-whitespace landmarks; I have nothing against parenthesis, coming from lisp and all.

@satyr
Copy link
Contributor

satyr commented Jun 22, 2012

I have nothing against parenthesis, coming from lisp and all.

In that case I'd recommend sticking with lispy variants, in which you have many better choices (ClojureScript, Slip to name a few) with unlimited possibilities via macros.

@gkz
Copy link
Owner

gkz commented Jun 22, 2012

@adrusi, you can use parentheses instead of do if you want

new Ext.util.KeyMap(
  target: Ext.getDoc()
  binding:
    * key: Ext.EventObject.L
      alt: yes
      defaultEventAction: "preventDefault"
      handler: -> app.sendEvent "changeListView"
    * key: Ext.EventObject.UP
      defaultEventAction: "preventDefault"
      handler: -> app.sendEvent "upKeyIsPressed"
)

@ghost
Copy link
Author

ghost commented Jun 22, 2012

In case of

if f
  name: "foo"
  true

Perhaps we can do:

if f do
  name: "foo"
  true

In that way we don't have to be forced typing do everywhere when we don't have to.

Just like executing a function with ! when we have to use it, and ignoring it when we don't.

Even when we have to use do I feel that we can use:

if f \
  name: "foo"
  true

indicating that it's a new line. Just like in unix.

Having do standing for 2 different things is not good practice.

@adrusi
Copy link

adrusi commented Jun 22, 2012

@johnnywengluu +1 for backslash. As ugly as it is, it's what's used in other languages (python, shell) and is in fact 1 less character

@satyr I tried clojurescript, and I like it. The thing is, I'm also a big javascript fan, and js is my main language, so I also really like these language projects that are closer to js. I'm not saying that clojurescript doesn't have fantastic interop, but coffeescript derivatives don't have a need for interop at all.

@ghost
Copy link
Author

ghost commented Jun 22, 2012

@adrusi yes, also, it will only be used when needed, which is perhaps never.

I think people would like to do:

if f name: "foo",  true

instead of the earlier mentioned one.

Let our code be cleaner without all these do keywords. It's an downgrade from CoffeeScript in this case

@satyr
Copy link
Contributor

satyr commented Jun 23, 2012

@johnnywengluu:

Perhaps we can do:

if f do
  name: "foo"
  true

In that way we don't have to be forced typing do everywhere when we don't have to.

Then we'd have to type do in most if though.

if f \
  name: "foo"
  true

\ is taken for unspacing/line-continuing which is more essential.

@adrusi:

I also really like these language projects that are closer to js

Pretty sure there are JS lisps that are. How about Sibilant?

@adrusi
Copy link

adrusi commented Jun 23, 2012

@satyr if the following becomes a legal syntax:

f name: "foo"
  other-name: "bar"

(it might already be) then do is line-continuing. But it's not that big of a deal, as I explain below.

I think do makes sense in if more than it does for its current application, but I'm in no way supporting requiring do for every if. Perhaps rename do to begin to make more sense?

And Sibilant is just bad, at one point I was interested and even forked the project and messed around with the source, but it's really quite bad.

Really, Coffeescript-like languages are fine for me, I'm just saying that it can get frustrating when avoiding parenthesis and braces becomes such a big deal to people that they come up with new syntaxes to avoid them, even when the new syntaxes mean more overall characters. Why can't we just be content with:

if f {
  name: "foo"
}, true

which IMO is easier to mentally parse than

if f do
  name: "foo"
  true

because it provides visual landmarks separating the 2 arguments.

@adrusi
Copy link

adrusi commented Jun 23, 2012

actually, I'd like to point out that:

if f do
  name: "foo"

does not compile because the end of the argument list would be ambiguous, for example:

if f do
  name: "foo"
  a++
  a + 2

is that

if (f({name: "foo"}, a++)) { return a + 2; } // however implicit returns are handled in this case, closures, ternaries, whatever

or

if (f({name: "foo"})) { a++; return a + 2; }

@satyr
Copy link
Contributor

satyr commented Jun 23, 2012

I think do makes sense in if more than it does for its current application, but I'm in no way supporting requiring do for every if. Perhaps rename do to begin to make more sense?

Python does this with requiring : for the start of block instead of do or begin. Removing this requirement is one of the best aspects of CoffeeScript syntax.

if f do
  name: "foo"

does not compile

Ritht, that if lacks the body part. Compare:

if f do
  name: "foo"
then
  a

@adrusi
Copy link

adrusi commented Jun 23, 2012

@satyr oh, so having a block in the predicate requires then? that's cool, I hadn't thought of that.

@satyr
Copy link
Contributor

satyr commented Jun 23, 2012

Yeah, since you need to somehow dedent and then indent again. Coco's then is simply ignored before an indented block for cases like that.

$ coco -bcs
  if a then
    b

if (a) {
  b;
}

$ coffee -bcs
  if a then
    b

Error: Parse error on line 1: Unexpected 'THEN'

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

No branches or pull requests

4 participants