COMMUNITY

When will support js-es=2019?

when will support js-es=2019?

In ES2019, private class fields are defined using a hash # prefix:

class MyClass {

  a = 1;          // .a is public
  #b = 2;         // .#b is private
  static #c = 3;  // .#c is private and static

  incB() {
	this.#b++;
  }

}

let m = new MyClass();

m.incB(); // runs OK
m.#b = 0; // error - private property cannot be modified outside class

Never? Seriously though, why would we need to implement every really bad idea JS community comes up with?

CS have @:private meta which marks a class field as being private. I don’t know if anyone uses this.

haha, because we have many development group, somebody just only uses originally js for development.

why do you think it’s very bad idea # for private?

Well, it has to be the ugliest syntax I’ve seen in a long time…

3 Likes

Hmpf. I don’t like the syntax myself, but I’d say the bashing is about as obnoxious. We’re talking about generated code.

The important question to ask about our output is whether or not it can be improved in terms of interoperability. For example ES6 classes were actually needed for something - IIRC it was some framework or custom html elements … or both?

If you feel like you can make a good point why this would make the generated JS easier to use from “native” JavaScript, that’s a great basis for discussion. Wanting it because it’s the latest hip thing is not. Especially because this particular feature is currently only supported by Chrome so in the end it’s going to have to be transpiled out anyway. All changes require effort to perform and maintain - especially if it’s support for a proposal that’s deemed experimental. You’ll need a convincing use case to motivate the team to exert that effort. Even more so if it requires overcoming their personal dislikes :wink:

3 Likes

Haxe’s “private” is more like “protected”, isn’t it? ES2019’s #prop is true private I think.

Like @back2dos said, it is about generated code, not Haxe code. Class field being private make sense when making library out of Haxe code for specific target, where developer continues work using target language like JS for example.

It’s not just about code generation but semantics: if you make a Haxe class with private fields, you can extend it (in Haxe and JS) and access these private fields because they are “protected” in reality. You could break the transpiled Haxe code by using “true private” JS fields.

That’s why CS have @:private meta, to let developer choose what will be private and what will stay protected

2 Likes

is there a simple way add some Marco code for add ‘#’ before ?

Simple way, no. But it is not so complicated. For example if you have

class MyClass {
    @:private var i:Int;
    public function new() {}
}

you need to register macro callbacks

class Macro {
#if macro
    static var types:Array<Type>;

    public static function callbacks() {
        haxe.macro.Context.onGenerate(function(t) {
            // store all types going to be generated
            types = t;
        });
        haxe.macro.Context.onAfterGenerate(function() {
            // read types and look for meta
            switch (haxe.macro.Context.getType("MyClass"))
            {
              case TInst(cl,_):
                var f = cl.get().fields.get();
                trace(f[0].meta.get());
              case _:
            }
            // modify .js file afterwards
	});
    }
#end
}

and add --macro Macro.callbacks() to your build.hxml file.

You have to write a code by yourself which iterates over types, looks for custom meta and modifies (by adding #) generated .js file afterwards. In case you are using custom JS generator which creates multiple files, you have to take care about that as well.

1 Like

src/Macro.hx:18: characters 27-31 : Uncaught exception field access on null

	import haxe.macro.Type;
	class Macro {
		#if macro
			static var types:Array<haxe.macro.Type>;
		
			public static function callbacks() {
				haxe.macro.Context.onGenerate(function(t) {
					// store all types going to be generated
					types = t;
				});
				haxe.macro.Context.onAfterGenerate(function() {
					// read types and look for meta
					switch (haxe.macro.Context.getType("MyClass"))
					{
					case TInst(cl,_):
						var f = cl.get().fields.get();
						trace(f[0].meta.get());
					case _:
					}
					// modify .js file afterwards
			});
			}
		#end
		}

That’s example assuming above class MyClass is provided, where first field contains meta. Example is hard-coded. As I said, you have to write your own code which iterates over types looking for meta(s)

The @:private point is good - that’s a non-ambiguous solution and it might be fair to request compiler support for this feature on https://github.com/HaxeFoundation/haxe/

Even putting aside my strong dislike for this feature, this is way too early to adopt it. Let’s at least wait for support in firefox before considering that.

Edit: note that haxe still supports IE8 afaik, so generating code (and moreover allocate time to develop this, since we’re not talking about accepting a PR but actually having to implement it) that only works on recent nodejs/chrome seems a little out of place.

At least custom html elements (v1 or both v0 and v1, I don’t remember), since they need ES6 classes. Not sure about frameworks.

@kLabz It was also needed for VSCode extensions - the VSCode extension API requires you to subclass ES6 classes in some places.

Well, I think it is not very important to wait for it. Because the main reason for private fields is the use of generated .js as a library in existing js projects which are already using Babel to achieve browser’s support.


Using Haxe output (which is a pretty common scenario) as a library is a good reason for almost all targets to support @:private meta on fields :slight_smile:

Not to be that guy but Haxe doesn’t have real privates. Our private keyword is actually a protected keyword, if you look to other code languages. Once in a while I would like to have real private, because I have to deal with OOP. With real I don’t mean isn’t hackable with @:access or @:privateAccess (like the es2019 one, which is very strict about it) but where I can define a private with same name in sub or parent class without issues.
Now I think changing our private to protected and introducing actual private is to big of a change, so that will never happen. But the hashtag in combination with private (as ugly as it might look) might help us getting realer privates, maybe?

private var x:Int; // protected private
private var #y:Int; // realer private

If it is just about generated code, I think it shouldn’t be that hard to support it using @:native, as alternative. At the moment that generates something that uses runtime reflection.

@:native("#x") private var x:Int;