gosukiwi / Blueberry

A beautiful programming language with clean syntax which compiles to PHP
MIT License
63 stars 10 forks source link

Variable functions and closures aren't supported #29

Closed hikari-no-yume closed 9 years ago

hikari-no-yume commented 10 years ago

Blueberry doesn't support PHP's closures yet, which is a shame, because they're really cool. Perhaps something like the following could work:

myClosure = def foo(bar) use (a, &b)
  return a + b + bar
end

We could also clone Hack's ==>, perhaps just making it -> like CoffeeScript since we don't have the conflict PHP does. It auto-imports referenced variables from surrounding scope:

myClosure = (bar) -> a + bar
myClosure = (bar) -> do
  return a + b + bar
end

The connected issue is variable functions. In PHP, you can do this:

$x = 'strlen';
$x('foobar');

But in Blueberry, it's currently not possible to do this, since there aren't any sigils. That's really quite a shame. I'm not sure how to solve this.

One approach would be, like CoffeeScript, to change how variables are scoped. If you had earlier declared a variable called foobar in your script, then we'd compile the Blueberry code foobar() to PHP $foobar(), but if you hadn't, we'd compile it to PHP foobar(). This would mean we'd have to explicitly declare variables global at the top level... which would probably be good thing! That, or get rid of them entirely.

Another approach is what Snowscript does, where all function declarations are done as variables. I really don't like that idea, though.

gosukiwi commented 10 years ago

I really like the Coffeescript closure syntax more than Hack's.

If we solved it with a scope change we would need to add some complexity to the AST parser, which wouldn't be too bad but I'd like to stay away from now. Maybe adding some syntax for function calls like that... We'll I'm open to suggestions :stuck_out_tongue:

Should we add context to all functions? Compile functions like Snowscript do? Create a new syntax rule?

gosukiwi commented 9 years ago

I really like this syntax

myClosure = (bar) -> a + bar
myClosure = (bar) -> do
  return a + b + bar
end
hikari-no-yume commented 9 years ago

That works well :)

Main issue is the implicit variable capture.

gosukiwi commented 9 years ago

Yeah I think it's going to have to be

myClosure = (bar) use (a) -> a + bar
myClosure = (bar) use (a, b) -> do
  return a + b + bar
end
hikari-no-yume commented 9 years ago

Maybe.

gosukiwi commented 9 years ago

As for calling variable functions... Certainly a() would get compiled to a();. I'd say the simplest solution is add some syntax construct to know when it's supposed to be a regular function call and when a variable function call.

For example, $a() could get compiled to $a();. But adding the $ character, might be confusing. Something I thought maybe was doing call(a, "arg1", 2, 3) and compile that to $a('arg1', 2, 3);.

gosukiwi commented 9 years ago

Okay I implemented it the hard way in 664073591ec5c334db676fb1b1fc649105e6af80. I added a very simple scope collector/state manager. So now we have access to all assigned variables, and also the ones in the parameters. Just a note: Class attributes cannot be closures, because it would be just silly.

Summing it up, right now you can do

a = () -> 2
a()
b()

And it will compile to

$a = function () { return 2; };
$a();
b();
hikari-no-yume commented 9 years ago

Awesome :)

Does this do implicit variable capture too? Because with the same infrastructure you can do that.

gosukiwi commented 9 years ago

You mean like adding the variables in the current scope to the closure's use automatically?

hikari-no-yume commented 9 years ago

No, just the ones you choose to use, e.g.

a = 3
b = 2
c = (z) -> z + b

which would result in

<?php
$a = 3;
$b = 2;
$c = function ($z) use ($b) { return $z + $b; };

or

a = 3
b = (i) -> (j) -> i + j + a

resulting in

<?php
$a = 3;
$b = function ($i) use ($a) { return function ($j) use ($a, $i) { return $i + $j + $a; }; };

This would work similarly to Hack's lambda functions which have the ==> syntax:

http://docs.hhvm.com/manual/en/hack.lambda.examples.php

gosukiwi commented 9 years ago

Ah I see now. I'll give that a shot later today.

hikari-no-yume commented 9 years ago

Incidentally, it's something I want to add to PHP proper, but I'm too focussed on certain other things just now.

gosukiwi commented 9 years ago

Interesting! This was harder than I expected. Mostly because I have to parse a block, and actually see what variables that block uses, and the context that block is run. I implemented a dummy solution in a6d76a98506a39fb1c425b1ee1c1309a55d6135e. If no use is specified it will just include all the variables defined in the parent context. Will look at this closer eventually. For now I'd like to give the languages some other features such as static methods :)

gosukiwi commented 9 years ago

Moved discussion to #39