It looks like the compiler is not maintaining |This| parameter signatures correctly for methods which take an it-block:
class Foo
{
new make(|This| f) {}
Void bar(|This| f) {}
static Void main()
{
t := Foo#
echo(t.method("make").params.first.type)
echo(t.method("bar").params.first.type)
}
}
// prints
C:\dev\fan\src>play
|play_0::Foo->sys::Void|
|play_0::Foo->sys::Void|
For constructors This is always the same as the declaring class, so this isn't a problem. For for a method like bar or Obj.with the parameter will be incorrectly typed.
brianSat 3 Apr 2010
Promoted to ticket #1056 and assigned to brian
tacticsSat 3 Apr 2010
The This type isn't allowed as a parameter type anywhere else. Obj.with is the only exception.
brianSat 3 Apr 2010
The This type isn't allowed as a parameter type anywhere else. Obj.with is the only exception.
Actually I do allow any method to have a it-block function signature. A good example would be if we added OutStream.use:
OutStream.use(|This| f)
WebOutStream(out).use
{
// it typed as WebOutStream
}
So I think we want to allow that.
tcolarSat 3 Apr 2010
Right, I put a workaround for now in my IDE for with(), which is currently the only place a THIS parameter is used in the fantom distro code.
But you are allowed to write your own (as it says in the "closure" page), so it would be good to fix it at some point.
tacticsTue 6 Apr 2010
Actually I do allow any method to have a it-block function signature.
This seems like a small inconsistency in the type system. Maybe you can explain.
This code does not compile.
class Main
{
static Void main()
{ }
static Void test(This f)
{ }
}
The error is that the test method cannot take a This parameter. Yet it has the same signature as an it-block.
It seems as if the |This| is not literally a function of This. Rather it's a special case.
andyTue 6 Apr 2010
I would assume thats cause its a static method - so error seems correct here - haven't looked thru the code tho.
tacticsTue 6 Apr 2010
I would assume thats cause its a static method
That's not the case. I tried it both ways (but I figured to demonstrate it here as static because a static method is closer to a function semantically than a non-static method.
The it-blocks are handy, but they sure do complicate the language.
brianWed 7 Apr 2010
The error is that the test method cannot take a This parameter. Yet it has the same signature as an it-block.
Using This in a parameter position is contra-variant (or a weird variation of it) which is why I don't support it. Functions work in a flipped variance mode, so it works out ok for |This|. Of course nothing is actually based on a formally proved type system.
tacticsWed 7 Apr 2010
I wish I had gotten farther in my B. Pierce type theory book :)
I think I understand. To preserve the method's contract, you have to be more forgiving in what you accept as input and stricter in output. Since This takes on a stricter type when called from a subclass, it breaks the contract. (But returning This is perfectly acceptable).
In the case of a function, the This type doesn't really make sense, since a function is not associated with a type. So like I said above, |This| isn't really related to covariance. It's just syntax for an it block.
This makes more sense to me now.
Edit: I'm trying to work this out from the specs I understand about type theory, and I take back what I said. |This| does seem to make sense exactly as it is. It's just weird :) When you pass a This block, you end up with a type that looks like this (using ML-like sytnax): (This -> a) -> b (for some types a and b). This type is something like "double contravariant", which is just covariant, and thus, contract preserving.
brian Sat 3 Apr 2010
It looks like the compiler is not maintaining
|This|
parameter signatures correctly for methods which take an it-block:For constructors
This
is always the same as the declaring class, so this isn't a problem. For for a method likebar
orObj.with
the parameter will be incorrectly typed.brian Sat 3 Apr 2010
Promoted to ticket #1056 and assigned to brian
tactics Sat 3 Apr 2010
The
This
type isn't allowed as a parameter type anywhere else.Obj.with
is the only exception.brian Sat 3 Apr 2010
Actually I do allow any method to have a it-block function signature. A good example would be if we added
OutStream.use
:So I think we want to allow that.
tcolar Sat 3 Apr 2010
Right, I put a workaround for now in my IDE for with(), which is currently the only place a THIS parameter is used in the fantom distro code.
But you are allowed to write your own (as it says in the "closure" page), so it would be good to fix it at some point.
tactics Tue 6 Apr 2010
This seems like a small inconsistency in the type system. Maybe you can explain.
This code does not compile.
The error is that the
test
method cannot take aThis
parameter. Yet it has the same signature as an it-block.It seems as if the
|This|
is not literally a function ofThis
. Rather it's a special case.andy Tue 6 Apr 2010
I would assume thats cause its a static method - so error seems correct here - haven't looked thru the code tho.
tactics Tue 6 Apr 2010
That's not the case. I tried it both ways (but I figured to demonstrate it here as static because a static method is closer to a function semantically than a non-static method.
The it-blocks are handy, but they sure do complicate the language.
brian Wed 7 Apr 2010
Using
This
in a parameter position is contra-variant (or a weird variation of it) which is why I don't support it. Functions work in a flipped variance mode, so it works out ok for|This|
. Of course nothing is actually based on a formally proved type system.tactics Wed 7 Apr 2010
I wish I had gotten farther in my B. Pierce type theory book :)
I think I understand. To preserve the method's contract, you have to be more forgiving in what you accept as input and stricter in output. Since
This
takes on a stricter type when called from a subclass, it breaks the contract. (But returningThis
is perfectly acceptable).In the case of a function, the
This
type doesn't really make sense, since a function is not associated with a type. So like I said above,|This|
isn't really related to covariance. It's just syntax for an it block.This makes more sense to me now.
Edit: I'm trying to work this out from the specs I understand about type theory, and I take back what I said.
|This|
does seem to make sense exactly as it is. It's just weird :) When you pass aThis
block, you end up with a type that looks like this (using ML-like sytnax):(This -> a) -> b
(for some types a and b). This type is something like "double contravariant", which is just covariant, and thus, contract preserving.You learn something new every day :)
brian Tue 11 May 2010
Ticket resolved in 1.0.53
Fix reflection to use correct it-block signature