In Haxe (JS Target) is there a way to make static members available to another class as if it was its own? - metadata

I have this Haxe class that is growing quite large. It consists mostly of static methods & properties. (It's a module set to compile as JS target).
I would like to separate some of the complex static functions into another class.
Is there any way to mark it with a metatag / indicate the other class is an "extension" to the original class?
Something like #:native("OriginalClass") class OtherClass {...}
The goal is to avoid having to write the full variable access (ex: OriginalClass.LOG_QUEUE vs. LOG_QUEUE) or clutter the imports with each OriginalClass's static methods / properties used at the top of the OtherClass. Basically, something to make it aware that it "is" using the same members as the OriginalClass (whenever an 'undefined' one is found, at compile-time).
Example:
If OriginalClass has static var LOG_QUEUE:Array<String>; then OtherClass would be aware that any usage of LOG_QUEUE compiles to this JS code OriginalClass.LOG_QUEUE

Alright, got a solution after discussing with Dima Granetchi from the Haxe experts group on Slack.
Now, although this will still generate the OtherClass that makes use of the OriginalClass's static members, you can cut down on the quantity of import statements for most (if not all) of the module/class's static members by using the wildcard * symbol, like in this example:
// OriginalClass.hx
package somePackage;
class OriginalClass {
public static var LOG_QUEUE:Array<String>;
public static function main() {
LOG_QUEUE = [];
OtherClass.doSomething();
}
public static function doSomethingOriginal() {
LOG_QUEUE.push("World!");
}
}
// OtherClass.hx
import somePackage.OriginalClass.*; // <-- Demonstrating the WILDCARD (*) symbol
class OtherClass {
public static function doSomething() {
LOG_QUEUE.push("Hello"); //Resolved to OriginalClass.LOG_QUEUE
doSomethingOriginal(); //Resolved to OriginalClass.doSomethingOriginal()
}
}
Although this is a minimal example, it becomes more useful when you have a few different dozen static members used in your OtherClass.
Note
TypeDefs defined in the OriginalClass used inside the OtherClass doesn't seem to get recognized/resolved (may be due to missing public accessor, but I was unable to set it on my typedefs). You can always import those specific TypeDefs with individual import statements, like so:
//Somewhere at the top of OtherClass.hx...
import somePackage.OriginalClass.MyTypeDef;

Related

private Helper class with public static func access modifier

I think I probably have some blind spot. The following code in test target actually works that I thought it should not: (MyHelper is private already, but the caller still can use myHelperFunc())
// both MyClass and MyHelper are in the same file
class MyClass: XCTestCase {
func testDoWork() {
MyHelper.myHelperFunc()
}
}
private class MyHelper {
static func myHelperFunc() -> String {
return "something"
}
}
If I move the code to main target (delete the XCTestCase), compiler immediately flag MyHelper is not accessible that seems the right behavior? Is there something specific for test target that I missed?
private at file scope is equivalent to fileprivate.
#testable import makes internal code accessible to a test target.
Access Levels in The Swift Programming Language explains how private works:
Private access restricts the use of an entity to the enclosing declaration, and to extensions of that declaration that are in the same file.
"The enclosing declaration" of MyHelper is "the file." This is perhaps a bit more clearly stated in the Declaration Modifiers section of the Swift Language Reference:
private
Apply this modifier to a declaration to indicate the declaration can be accessed only by code within the declaration’s immediate enclosing scope.
Again, the "enclosing scope" of MyHelper is the file. If MyHelper were enclosed in some other class, then it would be limited to that scope rather than the whole file:
// Things change if MyHelper has a different enclosing scope than MyClass.
class MyClass {
func testDoWork() {
MyHelper.myHelperFunc() // Cannot find 'MyHelper' in scope
}
}
class C {
// MyClass can't access C.MyHelper now.
private class MyHelper {
static func myHelperFunc() -> String {
return "something"
}
}
}
In your example, myHelperFunc() has no annotation, so it initially receives the default level of internal. This is noted in Access Levels again:
Default Access Levels
All entities in your code (with a few specific exceptions, as described later in this chapter) have a default access level of internal if you don’t specify an explicit access level yourself.
However, as noted in "Guiding Principle of Access Levels:"
No entity can be defined in terms of another entity that has a lower (more restrictive) access level.
It is not allowed for MyHelper.myHelperFunc() to have a broader access level than its encoding type (MyHelper), so it's limited to file scope (which is effectively the same as fileprivate).

Declare variable outside any class: why is it possible

I have a file fancy_button.dart for a custom Flutter widget FancyButton which is like:
class FancyButton extends StatefulWidget {
// ...
}
class _FancyButtonState extends State<FancyButton> {
// ...
}
// Declaration outside any class:
Map<_FancyButtonState, Color> _buttonColors = {};
final _random = Random();
int next(int min, int max) => min + _random.nextInt(max - min);
// ...
The application works just fine. Notice that I declare and use some variables outside any class. Now my question is: how is it even possible? Shouldn't everything be inside a class in Dart, like Java?
No, Dart supports variables and functions defined in global space. You can see this with the main() method which are declared outside any class.
Also, global variables (and static class variables) are lazy evaluated so the value are first defined when you are trying to use them. So your runtime are not going to slow down even if there are a bunch of global variables there are not used.
Are you coming from Java before touching Dart?
Basically, Dart is not single-class-single-file like how Java works. Yes, it does support Object Oriented Programming (in kinda different way). The behavior of constructor is different. There is no public, private, and protected keywords. Please just refer to the official docs.
Anyway, you don't need a complex public static void main(). The real entry point is main(). Unless you define that function, you won't be able to run a file in command line.

How to build an abstract with a Haxe macro?

I couldn't find any example code or tutorial floating around that creates abstracts with macros.
//Class code ReflectionClassInfo.hx
#:build(ReflectionClassInfoMacro.build())
abstract ReflectionClassInfo({}) from ({}) to ({}) {}
//Driver code
var r=new ReflectionClassInfo();
//Immeditately makes the compiler complain about there is no constructor
How can I fix the compiler error?
One thing that's important to realize is that there isn't really any difference between build macros for classes and abstracts. In both cases, they build fields, meaning that they have to return an array of haxe.macro.Expr.Field. So any documentation or code example that applies to one also applies to the other.
The easiest / most readable way to fix the compiler error in your example is by using class reification, so that the constructor can be declared with regular Haxe syntax:
import haxe.macro.Context;
import haxe.macro.Expr.Field;
class Macro {
public static function build():Array<Field> {
var fields = Context.getBuildFields();
fields = fields.concat((macro class {
public function new() {
this = {};
}
}).fields);
return fields;
}
}
class Main {
static function main() {
new Abstract(); // compiles
}
}
#:build(Macro.build())
abstract Abstract({}) from {} to {} {}

Better way to do class type alias?

From time to time, I would like to call a class differently depending on the context or to reduce duplication.
Let's assume, I have the following classes defined:
// in file a.dart
class A {
final String someprop;
A(this.someprop)
}
// in file b.dart
abstract class BInterface {
String get someprop;
}
class B = A with EmptyMixin implements BInterface;
For this syntax to check out, I have to define EmptyMixin so that the syntax is OK.
Do you know of a better/prettier way to do this "aliasing" in Dart?
I'm afraid the way you're doing it is the prettiest way to do this at the moment. There is a very old, but still open and active issue: https://github.com/dart-lang/sdk/issues/2626 that proposes the typedef B = A; syntax for aliasing types.

Creating namespaces with classes in Swift

I am a newb to Swift, I am looking to create some nested namespaces, like so:
import Foundation
public class Foo {
class Moo {
class Bar{}
}
}
and then I can do:
var f = Foo.Moo.Bar()
do we not need to use the static keyword here? I don't understand why I don't need to do it like so:
import Foundation
public class Foo {
static class Moo {
static class Bar{}
}
}
var f = Foo.Moo.Bar()
can anyone explain why?
Foo.Moo.Bar is just the name of the class. You're not accessing a particular instance of Foo or Moo when you do this:
var f = Foo.Moo.Bar()
You're just creating an instance of the Foo.Moo.Bar class.
can anyone explain why?
Can you explain why not? What would a static class even mean? How can a class be static? Maybe you come from a language where that keyword means something special in this context?
In any case, in Swift it wouldn't mean anything. The word static has just one very simple meaning in Swift: A type member, i.e. a property (var or let) or method (func) is either an instance member or a type member; to distinguish the latter case, we say static (or class). This is neither of those. It is, as you rightly say, merely a namespaced type.