Re: [dart-misc] Closures are not comparable?

150 views
Skip to first unread message
Message has been deleted

Kathy Walrath

unread,
Mar 13, 2013, 1:57:29 PM3/13/13
to General Dart Discussion


On Wed, Mar 13, 2013 at 10:03 AM, mezoni <andrew...@gmail.com> wrote:
Closures are not comparable?

Always get the same result of the comparison operation of closure to itself - "false". 
Even when comparing with "identical" method.
Is this normal?

--
Consider asking HOWTO questions at Stack Overflow: http://stackoverflow.com/tags/dart
 
 

Message has been deleted

Florian Loitsch

unread,
Mar 13, 2013, 2:33:40 PM3/13/13
to General Dart Discussion, Karl Klose
CCed Karl who has worked a lot on types. (see question on runtimeTypes below).

On Wed, Mar 13, 2013 at 7:21 PM, mezoni <andrew...@gmail.com> wrote:
Thanks. I did not know about it.
It prevents to use callbacks as handles for himself.
Because this will not work.
//------
var handle = callback;
queue.enqueue (handle);
/ / And later
queue.indexOf (handle) / / is always -1
 
This should work.
What doesn't work:
class A {
  callback() { ... }  // instance method
  foo() {
    queue.enqueue(callback);
    // And later:
    queue.indexOf(callback);
  }
}

Think of it as if methods had a hidden getter that created a new closure:
class A {
  callback() { ... }  // instance method

  get callback => () => this.callback();  // hidden getter.

  foo() {
    queue.enqueue(callback);  // uses getter.
    // And later:
    queue.indexOf(callback);  // uses getter.
  }
}




Also one similar question.
I also do not understand runtime types are immutable or not?

var type = String;
var value = 'message';
var valueRuntimeType = value.runtimeType;
print('type: $type');
print('valueRuntimeType: $valueRuntimeType');
print('type.runtimeType: ${type.runtimeType}');
print('valueRuntimeType.runtimeType: ${valueRuntimeType.runtimeType}');
print('valueRuntimeType == type: ${valueRuntimeType == type}, may be true');
print('valueRuntimeType.runtimeType == type.runtimeType: ${valueRuntimeType.runtimeType == type.runtimeType}');

type: String
valueRuntimeType: String
type.runtimeType: _Type
valueRuntimeType.runtimeType: _Type
valueRuntimeType == type: false, must be true
valueRuntimeType.runtimeType == type.runtimeType: true
That looks strange. I hope Karl knows more.

Or is it written that this is it should be so?

--
Consider asking HOWTO questions at Stack Overflow: http://stackoverflow.com/tags/dart
 
 



--
Give a man a fire and he's warm for the whole day,
but set fire to him and he's warm for the rest of his life. - Terry Pratchett
Message has been deleted

Alex Tatumizer

unread,
Mar 13, 2013, 4:05:48 PM3/13/13
to mi...@dartlang.org
Please explain WHY this doesn't work

var handle = callback;
queue.enqueue (handle);
/ / And later
queue.indexOf (handle) / / is always -1

What, handle is not equal to itself?
The example from a tour of dart says:
splitClosure2 = splitClosure1;
assert(splitClosure1 == splitClosure2);
 

Ladislav Thon

unread,
Mar 13, 2013, 4:34:50 PM3/13/13
to mi...@dartlang.org
Please explain WHY this doesn't work

var handle = callback;
queue.enqueue (handle);
/ / And later
queue.indexOf (handle) / / is always -1


I believe this should work. If not, it's a bug.

What doesn't work is

callback(...) {
  ...
}
...
queue.enqueue(callback);
...
queue.indexOf(callback);

Because it is the same as

callback(...) {
  ...
}
...
queue.enqueue( (...) => callback(...) );
...
queue.indexOf( (...) => callback(...) );

LT
Message has been deleted

Alex Tatumizer

unread,
Mar 13, 2013, 4:52:04 PM3/13/13
to mi...@dartlang.org
Any known motivation for rules like this?
If yes, would it still be possible to provide some id, so that at least ids of these closures would be equal
so
s.split.id==s.split.id at least
P.S. I don't believe I'm really writing this. Reminds a character of  Stanislaw Lem's novel (Ion Tihiy) who split into two copies, each one trying to figure out which of two Ions is real, and which is fake.


--
Message has been deleted

Alex Tatumizer

unread,
Mar 13, 2013, 7:05:49 PM3/13/13
to mi...@dartlang.org
> Closure: Task<T>(dynamic) => void from Function '_execute@0x3244f1c1':.
> Closure: Task<T>(dynamic) => void from Function '_execute@0x3244f1c1':.
> false
So we can still compare them using f1.toString()==t2.toString(), right?


Ladislav Thon

unread,
Mar 14, 2013, 1:20:48 AM3/14/13
to General Dart Discussion


> Any known motivation for rules like this?

What rules do you mean? If you closurize a function twice, you get two closures. And they are not equal.

Now maybe I'm a little imprecise here, as long ago, there were discussions about canonicalizing (you would say interning) some kinds of implicit closures (implicit closure = closure created by closurizing a function), specifically those created from top-level functions and static methods, and I don't remember what the current state is. Those closures would be equal, because they are identical. But again, I'm not exactly sure what the current state is.

Rule of thumb is: create the closure once, store it in a variable and use that variable. That's the first example that I said should work.

LT

Karl Klose

unread,
Mar 14, 2013, 4:44:21 AM3/14/13
to Florian Loitsch, General Dart Discussion
Although it is not required by the spec, it is reasonable to expect this to be true (and I think it is a bug in the VM). I filed a bug: https://code.google.com/p/dart/issues/detail?id=9136. Thanks for reporting this!

Karl

Alex Tatumizer

unread,
Mar 14, 2013, 9:28:01 AM3/14/13
to mi...@dartlang.org, Florian Loitsch
@Ladislav:
Somehow, I overlooked the fact that whatever is called Function in dart in fact doesn't correspond to javascript notion of Function - it's really a closure, e.g.
  Function f="abcd".substring;
  print(f(0,2));

This is a great feature, so I withdraw my sarcasm. I thought dart makes distinction between Function (as pointer to function "codes") and Closure, but it probably doesn't.
Won't it be better to call it Closure, not Function then, to avoid confusion?

Ladislav Thon

unread,
Mar 14, 2013, 9:45:32 AM3/14/13
to mi...@dartlang.org
Function is just something that can be called. Even this, I believe:

class Answer {
  call() => 42;
}

main() {
  var a = new Answer();
  print(a());
  print(a is Function);
}

Some Functions are in fact closures, meaning that they carry their lexical environment, but not all of them. I'm not sure about renaming Function to Closure, I think it would make some situations more clear and some less.

LT

Alex Tatumizer

unread,
Mar 14, 2013, 10:11:41 AM3/14/13
to mi...@dartlang.org
Probably you are right, but then things get a bit confusing indeed for anyone coming from javascript (huge army of potential dart users).
Look at "Tour of the dart language" - they are talking about functions AND closures, without elaborating on subtleties - but this are very important subtleties, deserved to be featured much more prominently.
 Needs to be better documented maybe?

Dirk Detering

unread,
Mar 14, 2013, 4:02:40 PM3/14/13
to mi...@dartlang.org

Function is something that can be called and maps its input parameters (0 to n) to its result (0 to 1).
It may have side effects or not.

Closure is a totally orthogonal concept of some object "closing" about the scope in which it was created, carrying that around with it.
It must not even be a function. Could be an anonymous class' instance.

It is a misconception that came up at the birth time of Ruby and Groovy to call a function-like thing that (even if only potentially) encloses a scope a "closure" and use these terms interchangeable.

Gilad Bracha

unread,
Mar 14, 2013, 4:07:52 PM3/14/13
to General Dart Discussion
Sorry to contradict, but the term closure has been used both as abstract description of closing over variables, and specifically for procedures/functions that do so long before Ruby or Groovy were so much as a glimmer in their designer's eye.
--
Cheers, Gilad

Alex Tatumizer

unread,
Mar 14, 2013, 4:12:48 PM3/14/13
to mi...@dartlang.org, mail...@googlemail.com
@Dirk: the most unexpected fact for me is that context is incorporated into "closure" automatically.
That is, when you write
var f=str.substring
 There's an optical illusion that you extract attribute from str, like normal attribute.
BUT in fact, "str" gets factored into returned function value.
Magic.

Dirk Detering

unread,
Mar 15, 2013, 1:43:20 AM3/15/13
to mi...@dartlang.org

Am 14.03.2013 21:07 schrieb "Gilad Bracha" <gbr...@google.com>:
>
> Sorry to contradict, but the term closure has been used both as abstract description of closing over variables, and specifically for procedures/functions that do so long before Ruby or Groovy were so much as a glimmer in their designer's eye.
>

Thanks Gilad.
What was new with Ruby/Groovy IMHO was the fact that functions are called closures even if they _don't_ close over any variable, moving to the notion of "closure is a function that can be passed around".
That exactly led to the idea that "Groovy has closures, Java not", what in this form is not true.

Dirk Detering

unread,
Mar 15, 2013, 2:06:40 AM3/15/13
to Alex Tatumizer, mi...@dartlang.org

Am 14.03.2013 21:12 schrieb "Alex Tatumizer" <tatu...@gmail.com>:
>
> @Dirk: the most unexpected fact for me is that context is incorporated into "closure" automatically.
> That is, when you write
> var f=str.substring
>  There's an optical illusion that you extract attribute from str, like normal attribute.

Well, the latter is sadly true.

But the above expression simply is a function definition in point-free style.

That is
var f=str.substring
is equivalent to:
var f= (x,y) => str.substring(x,y)

It is not 'str' that gets factored, but the expression 'str.substring'.

Now here you indeed build a "context" (=surrounding function), which closes over str, but that is not necessarily the case, and not necessarily uses this style, and thus why I said "orthogonal".

At least I assume that Dart works here like Haskell?
I.e. in the tradition of:

var f = (string x) => x.length

var g = (int y) => y * 10

var h = g compose f     //no parameter lists -> point free

Resulting semantically in
h = (string x) => g(f(x))

(Writing from my mobile so can't look things up now)

> BUT in fact, "str" gets factored into returned function value.
> Magic.

No. Simple transformation. Missing argument list on the right leads to additional parameter list on the left.

Alex Tatumizer

unread,
Mar 15, 2013, 1:15:17 PM3/15/13
to mi...@dartlang.org, Alex Tatumizer, mail...@googlemail.com
> No. Simple transformation. Missing argument list on the right leads to additional parameter list on the left.
Your conjecture is easy to verify (falsify?) by simple experiment. What do you expect to see printed here?
 var str="abcdef";
  var f=str.substring;
  print(f(0,3));
  str="01234";
  print(f(0,3));

Compare it with this:
 var str="abcdef";
  var f=(x,y)=>str.substring(x, y);
  print(f(0,3));
  str="01234";
  print(f(0,3));



Seth Ladd

unread,
Mar 15, 2013, 1:27:29 PM3/15/13
to General Dart Discussion
Some Functions are in fact closures, meaning that they carry their lexical environment, but not all of them. I'm not sure about renaming Function to Closure, I think it would make some situations more clear and some less.

Here's how I try to understand it:

Every time I do this:

var s = 'some string';
var splitClosure1 = s.split;

It's sort-of like doing this:

var s = 'some string';
var splitClosure1 = new Closure(s.split);  // I made up the new Closure part

In other words, when I reference a function by name, I'm really creating a new closure *at that point*. The key is "a new closure".  You can even call this "closurizing" the function.

So, if we view the code this way:

var splitClosure1 = new Closure(s.split);
var splitClosure2 = new Closure(s.split);

It makes more sense that splitClosure1 != splitClosure2

Hope that helps,
Seth

ps see also the discussion here: 


and


pps there was discussion early on to make closurization way more obvious. I personally feel it's a bit sneaky as it is, because it looks like you're "just getting a reference to the function as object" because it looks like a field access. One proposal was something like 'var splitClosure1 = s.split#'.  But I'm sure that ship has sailed so don't get too worked up about that syntax. :)

Alex Tatumizer

unread,
Mar 15, 2013, 1:38:15 PM3/15/13
to mi...@dartlang.org
@Seth, not to be misunderstood, I certainly LIKE the feature. This construct is a source of trouble in javascript, forces you to write f.call afterwards, and I keep forgetting the difference between f.call and f.apply, so need to go to mozilla reference every time :)

It's just that there's MAGIC there, and the magic has to be better emphasized in the tutorial. Especially the difference between javascript interpretation of Function and dart's.



Seth Ladd

unread,
Mar 15, 2013, 4:40:38 PM3/15/13
to General Dart Discussion
On Fri, Mar 15, 2013 at 10:38 AM, Alex Tatumizer <tatu...@gmail.com> wrote:
@Seth, not to be misunderstood, I certainly LIKE the feature. This construct is a source of trouble in javascript, forces you to write f.call afterwards, and I keep forgetting the difference between f.call and f.apply, so need to go to mozilla reference every time :)

It's just that there's MAGIC there, and the magic has to be better emphasized in the tutorial. Especially the difference between javascript interpretation of Function and dart's.


Thanks for the feedback. I agree, we need to continue to document these issues as we learn more about how people use Dart. 
Reply all
Reply to author
Forward
0 new messages