Closed bendmorris closed 6 years ago
The problem here is syntactic ambiguity. The compiler parses Array<Test
as a binary operation:
var Array = Std.random(42),
Test = Std.random(42);
trace(Array<Test/*> ... cannot put this here*/);
Scala doesn't have this problem, because their syntax is Array[Test]
. Perhaps you could use that? Other that than @:meta(var pickAName:Null<Test>)
will work, if that's any consolation. Perhaps we could allow for : SomeType
to be parse to EComplexType(macro : SomeType)
? It shouldn't be ambiguous, but it might lead to pretty confusing error messages if you do odd mistakes in ternary operator, e.g. decrement ? foo--- : foo++
. That's a pretty silly example, but perhaps there are likelier mistakes?
Right, I was thinking this could also be resolved simply by preferring well-formed parameterized type paths over binary operations. That should only cause problems where there is overlap such as a < b > c
which is intended as binary operations; but this usage seems extraordinarily rare (the example only makes sense if you've overridden the operators, because bool comparison doesn't make sense) and could be disambiguated with parens. Maybe there are other conflicts with bit shifts or parens that I haven't thought of.
: SomeType
is not a terrible alternative. Something like Array[Test]
would be easier to implement but I wouldn't want to introduce inconsistent syntax just for this.
Ok, let's try something different:
foo.Module.SubType<bar.Module.SubType>
foo.Class.CONSTANT<bar.Class.CONSTANT
Of course the comparison of static constants is unlikely. But then there's also the issue that constant expressions are valid type parameters: sys.db.VarChar<255>
.
Plus to implement this, the parser may have to do quite the look ahead. So I wouldn't be too optimistic about this.
While there would be a modest benefit of being able to write an expression like Array<Test>
instead of (_:Array<Test>)
, it's a good thing that types don't have to parse as expressions and that expressions don't have to parse as types. It allows to choose the syntax for each independently. Conflating the two means being more restricted and losing flexibility down the road.
Using a colon without the parens to introduce a type annotation would be excellent, but it unfortunately does introduce ambiguities with ternary (otherwise we'd actually have that syntax now).
Other than that, it'd be a quite an effort to support this, and given the limited developer resources, I doubt the investment would be justified.
Using a colon without the parens to introduce a type annotation would be excellent, but it unfortunately does introduce ambiguities with ternary
Would you care to be specific?
Short story: cond ? A : B : C
- where's the type?
This idea has been discussed on and off. Simon took at least two shots at it, and I also experimented with it. There's another conflict with case .. :
which isn't very pretty to work around. (if you're interested, see here and look for in_case
which only has been introduced there to deal with that ambiguity).
I didn't really bother much trying to get ternary to work, but Simon had come to the conclusion that to remain consistent, introducing expr : SomeType
would mean that ternary had to go.
You're not addressing the question. I understand the issue with ECheckType
- it just so happens that almost five years ago the conclusions you're now offering were put forward by me :P
This is a different matter. I'm saying an expression commencing with :
should parse a complex type next and yield EComplexType(theType)
. For case <expr>:
the :
is not in a leading position. Same goes for the ternary, where cond ? A : B
is valid and the :
simply is not. I don't see how this might cause ambiguity, but if you can think of something, please do. The only issue I see is that, as stated above, if you botch the syntax within a ternary operator, the resulting error might be confusing.
Oh.. alright. Syntax-wise there are no issues I see, then. What would be the type(s) of the resulting run-time value?
What would be the type(s) of the resulting run-time value?
It depends. If it's not a runtime value at all, then it should error, as would var x = Iterable;
. I guess var x = :Array<Int>
should be Array
but rather typed as Class<Array<Int>>
and for @:generic
classes it should actually select the particular specialization.
It seems like the runtime value question is already answered, because this already works:
typedef MyArray = Array<Test>;
class Test {
static function main() {
var a = MyArray;
trace(a);
}
}
Seems like :Array<Test>
should have the same result.
One question, is there an advantage to EComplexType()
over EConst(CComplexType(...))
? I ask because:
MyType
by itself parses to EConst, so it's consistentThere's two kinds of meta data:
@meta
which is runtime metadata, that can later be extracted at runtime with the haxe.rtti.Meta
api. For this metadata the restriction applies.@:meta
which is compile time only metadata. It is either used by the typer, the generator or a macro, but never makes it into the output. You can put anything you want as an argument, so long as it passes the parser.As for the rest, I don't know. But since pack.MyType
parses as EField
, EConst
wouldn't be my first pick. Especially since currently it always represents single token expressions. Hence I would opt for EComplexType
, but of course this is also subject to taste ;)
Sorry if I have overlooked this, but any syntactic change should go through https://github.com/HaxeFoundation/haxe-evolution
Evolution proposal: https://github.com/HaxeFoundation/haxe-evolution/pull/44
Seeing some unintuitive behavior regarding what is considered a constant or valid expression value/metadata argument.
Valid
Invalid (fails to parse)
Suggestion
The valid cases can be treated as Constants (CIdent) and there's no comparable structure for identifiers which represent types with parameters, so
A<B>
isn't a valid expression. However, an identifier (which may refer to a type) is not conceptually any more of a "constant" than a parameterized type name.How about a
CTypePath(p:TypePath)
? Mainly I want this so I can specify type paths as metadata arguments (without just using a String.)