-
-
Notifications
You must be signed in to change notification settings - Fork 682
Permit json syntax more generally for anon-types. #2185
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
Conversation
var obj:{"var":Bool} = {"var":true}; trace(obj."var");
+1 ... it happened to me way too often to have to work around the issue. |
I'm quite sure this is going to require some generator modifications as some generators handle escaping of target keywords only if they are not haxe keywords. I'm still in favor of this change. |
I'm against it. JSON notation is just a convenience to be able to copy/paste JSON into Haxe. I don't think we should allow any additional support for it as part of the type system. This would blur the difference between an actual object and a String Map. |
I won't try to argue against the blurring as I consider that rather subjective. I just don't see the value of forsaking all type-safety by using Reflect.field just because an external field happens to be named like a haxe keyword. |
Nicolas, if that's your worry, can we maybe make a difference then between what's "JSON" notation and what's simply trying to access a field that is a haxe keyword? I think it's a fair compromise. |
I don't think we should introduce a new specific syntax for accessing fields that are invalid in haxe (either keywords, or special chars), Reflect.field is enough IMHO |
Can we please split this discussion in two then, my changes are really two seperate things. On one side, there are the extensions that allow non-haxe identifiers to be represented in the type of an anon-object, which is really a much more important one. var obj = { "dynamic": true };
$type(obj); // Warning: {}
obj = { }; // compiles without error
obj = { "static": false }; // compiles without error And the real-life use case. writing externs for non-haxe libraries: extern class Example {
static function example(params: { "dynamic": Bool ... }) : SomeReturnType;
static function anotherExample() : { "dynamic": Bool };
} there is no 'good' way of doing things like this, exactly because of the way non-haxe identifiers are not represented in the type system, there's really only two ways of doing it: extern class Example {
static function example(params : {}) : SomeReturnType;
static function anotherExample() : {};
} which clearly is terrible, you completely lose the type information, you have no way of knowing from code hints, or from compiler errors that the params argument is an object with a field called dynamic, and there is no way of knowing what fields the return of anotherExample has. The alternative I presently use is: extern class Example {
static inline function example(params : {_dynamic:Bool}):SomeReturnType return untyped __js__("(function (parms) { params.dynamic = params._dynamic; return this.example(params); })").call(this, params);
static inline function anotherExample(): { _dynamic: Bool} return untyped __js__("(function () { var ret = this.anotherExample(); ret._dynamic = ret.dynamic; return ret; })").call(this);
} which apart from being completely specific to JS, produces some really horrible looking, and totally unoptimisable code, but is the only nice way of getting static typing for the haxe code. This of course assumes the external code isn't going to fail because of the extra _dynamic field on the object etc. On the other side of my changes, is having a way to then, without using Reflection which comes with no static type checks and again, produces sub-optimal code, to access fields of these externally provided objects that do not correspond to valid haxe field names. var obj = Example.anotherExample();
trace(Reflect.field(obj, "dynamics")); // compiles... oops there is no field called dynamics. Sigh. compared to var obj = Example.anotherExample();
trace(obj."dynamics"); // Error, obj has no field named dynamics I understand this syntax would be new, an alternative new syntax would be from C# using the @ modifier to have trace(obj.@dynamic); as a means of accessing a field that is a reserved word 'in haxe'. Personally I feel this isn't as good, because it still restricts us to what haxe considers a valid identifer in terms of things like only containing a-zA-Z0-9_ which may not be the case for the external library. It is also 'completely new' syntax, as opposed to |
@Simn I made some changes on my branch (Don't seem to reflected here after this request was closed, but they are there on my branch) for genphp, genjs and genas3 to support this too. No changes were needed for swf/c++/c#/java since access on anon-objects already goes through a level of indirection |
I support Luca on all the line. The pain he describes is real for whoever On Fri, Sep 20, 2013 at 6:08 AM, Luca Deltodesco
|
I also agree with Luca. We should make the external library integration as painless as possible. Actually the "@" syntax for C# had the same purpose - since C# is only one of many CLR language implementations, there should be a way to easily access an identifier that is invalid from C# but valid on another language. |
Same here, its always a pain when dealing with such situations. Of course if you only write everything in haxe that's not a big deal. But the reality is that you don't won't to reinvent the wheel when a native lib is already available. Adapting to such kind of problems is very important for haxe. |
btw. my feature request #1492 would also simplify working and defining interfaces for external libraries. |
would at least a metadata based solution be an option? typedef MyJson = {
@:native("var") var var1:String;
@:native("some-key") var someKey:Int;
} the definition is not pretty but using it would be straightforward: var x:MyJson = { var1 : "whatever", someKey : 1 } this would also mean that the native metadata becomes part of the type, because typedef Foo = {
var var1:String;
} because typedef Foo = {
@:native("var") var var1:String;
} i'm sure this solution would also have some problems, but it's just an idea... |
+1, I've described this same pain in #2164 |
Yes, @:native would work better here. Might require a "cast" for the JSon though, although we might be able to deal with it in some specific cases. |
While I'm glad for any kind of solution, the @:native one looks vastly inferior to what luca suggests. |
Yes, just for the json naming problem it doesn't looks nice, it adresses different problems which somehow overlaps with this specific one. |
On one side; @:native is the solution to naming problems with externs and looks like the de facto solution. I also like the lean approach deltaluca proposed but I see it as inconsistent with the rest of the renaming solutions in the lang and also I'm not sure it would not break a lot of ide tooling support regarding non standard member names. So, in the end, I'm not sold yet on any solution - any arguments? |
I'm closing this one, please add a @:native proposal or even better pull request. |
var obj:{"var":Bool} = {"var":true};
trace(obj."var");
i understand @Simn has said there was 'some' reason this sort of thing hasn't been added before, and whether the exact syntax would be wanted or not is to be decided.
However, even if we reject the obj."var" syntax (Although this is 'so' much better than Reflect use, especcialy since the lifting of the type restriction means such usage is staticly checked now), having the non-haxe-ident fields as part of the type is surely better than allowing things like:
var obj = {x:10};
obj = {x:10, "other_field": 20, "hahah you suck": 30 };
going through compile because the non-haxe idents are just 'not checked'.
The main usage for this sort of thing, like with json syntax itself is for working with js target, in my specific case, providing typed externs for a lib which uses non-haxe idents for object fields, and without this there's just no way to type it nicely without changing the field name and providing a horrible wrapper to then assign the real field using untyped js... ew.