My opinon on what Haxe should move towards to
I want to talk about what in my opinion should be done for Haxe in near-ish future. Haxe is in pretty good shape, so I don't think it needs a rewrite or anything, it is more about polishing and modernizing. Please note that what I'm going to write next is just my opinion, so feel free to reasonably disagree. :) Also note that I'll be mostly talking about technical stuff that requires good Haxe knowledge, so if you're new this might not make sense to you.
Rework Null<T>
type
Even if proper null-safety can't be achieved in Haxe (though we definitely should still try), the Null<T>
type surely should be abstract, not a typedef. This gives so much headaches and bugs in both macros and compiler internals, because typedef is supposed to be an alias, but in case of Null<T>
, it's not - on static targets, nullable types are very much different from non-nullable ones and the fact that you can easily lose the nullability aspect by mere using Context.follow()
is very annoying.
Rework RTTI and -xml output
The data format used by -xml
and haxe.rtti
is horrible, not only because it's XML, but also it's quite badly designed.
It should be reworked to a compact JSON-based format that easily maps to typedef'd structures. Removing the whole RTTI functionality
would work too, because often it's much better to write a macro that stores only the information you actually need in the run-time instead of everything. But as long as it's opt-in, I'm fine with it.
Rework Dynamic
I absolutely hate Dynamic
. It's VERY error-prone in general and moreover it always puts sticks in the wheels for actually good language/compiler features, such as analyzer, inline extern methods, method/operator overloading, etc.
Instead of current Dynamic
, we should have the Any
type that doesn't provide any field or array access and doesn't try to coerce to anything, but can be casted to a proper type. Much like the e.g. object
in C#. That way, returning Any
from a function shouldn't result in a monomorph type (the Unknown
), but should stay Any
. Everyone would win in terms of code quality. Even for low-level platform-specific code we could live without Dynamic
: just cast your whatever to a structure and work in a typed way (or use untyped
).
Also, implements Dynamic
and the resolve
magic should go away with this change (alternatives: abstract resolve and/or operator overloading).
It's quite a huge change, we could start with simply including Any
in the standard library and promoting its usage instead of Dynamic
.
Add method and operator overloading for classes
I'm not a fan of method overloading in general, but sometimes I feel like it's just the right solution for some things and I don't think it's impossible for Haxe to support it, especially if Dynamic
will be changed as described above. For a reference, one could look at how DuoCode implements C# method overloading on JavaScript by using name mangling. This should not be a problem in a statically typed world.
If it won't be implemented, Simon had two great ideas regarding this that should be a good compromise:
- allow extern-inline overload methods (so they are explicitly compile-time only without magic name mangling)
- operator overloading through static extension (so you can bring your operators with a
using
)
More on this topic, ArrayAccess<T>
for externs should be replaced with operator overloading and support specifying key type as well. And while I find the @:op(a[b])
syntax quite clever, I think we should have a proper syntax for this, like C#'s operator this[int x]
.
Rework function type
The current Arg1->Arg2->Ret
function syntax is quite bad. Not only because it's unfamiliar to most non-FP people, but also because it implies auto-currying for FP people AND (most importantly) it doesn't support argument names, which are very helpful for code self-documentation, auto-completion and IDE support (e.g. for the "generate callback method" functionality). It would be nice to change this syntax, at least to include names, like name1:Arg1 -> ?name2:Arg2 -> Ret
, but something without those arrows would be better. A nice syntax for the function type is I think the one from TypeScript: (arg1:Type1, arg2:Type)=>Ret
, and it would play really well with the commonly accepted short lambda syntax (x:Int, y:String) => "hello"
(and yes, I do want short lambdas please).
Improve variance
This is hard and few people really understand variance rules (e.g. I don't), but I think C# got it right and their variance system is actually better with explicit covariance and contravariance, which is useful when working with collections and interfaces.
Rework iterators
Currently, Haxe's Iterator
type relies on structure subtyping which implies runtime overhead on many static targets, which is
really bad for performance of such an important thing like iterators. It should be an interface instead. Also, the next/hasNext
rules aren't very clear, in .NET enumerators have better APIs with MoveNext
and Current
.
Clean-up standard library
Haxe std lib is fairly okay, but not great and it should be reviewed, most importantly:
- redesign process API
- add async io/networking API
- move stuff like web dispatch and SPOD out of the std lib to official haxelib projects
- add cross-platform unicode support
- generally review naming and package structure
- improve documentation (we need more structured way to describe function arguments, maybe adopt python-like doctesting)
- fix the Date APIs (e.g. handle utc/local times properly)
haxe.remoting.Proxy
,haxe.xml.Proxy
should move away from the compiler to@:genericBuild
macros- there should be a generic
Type<T>
alternative toClass<T>
andEnum<T>
for use inExprOf<T>
for function signatures in macro methods and macro static extension functions, because those can work with any type, not just class or enum.
Restructure and comment compiler source code
I absolutely love what Simon is doing with the Haxe's ocaml sources with refactoring and cleaning stuff up, but there's still a lot to do, and we should definitely start better commenting the source (follow the boyscout principle). OCaml is not hard at all, and with better structure and comments, I believe every macro power-user could hack the compiler.
Clean up metadata
Currently, situation with the metadata in Haxe is a bit of a mess, here's what I think should be done:
- think of the standard naming scheme for the metadata to prevent clashes (maybe even introduce namespaces)
- support typed metadata, add macro-"hooks" for the metadata (look at C# attributes for some inspiration)
Clean up syntax and old magic
Some Haxe syntax feels a bit "hacked-in" (maybe because initially it was, but nowadays there are some widely used language features with some syntax quirks), for example:
@:enum abstract
- this should useenum
keyword, not a metadata, because the sacred union of enum and abstract is deeply integrated into the compiler and thus deserve a proper syntax for it.-
structure types could be a bit friendlier:
- since the types have two different notations (
{a:Int, b:Int}
vs{var a:Int; var b:Int;}
), the structure extension syntax should also support;
at the end (e.g.{>Some, x:Int}
and{>Some; var b:Int;}
) - the short notation could also support read/write access for properties (e.g.
{a(default,null):Int}
)
- since the types have two different notations (
-
speaking of read/write access. I'm not a fan of the current default/null/never/get/set/dynamic stuff and I think at least
null
should be changed to something more obvious (private
maybe?). Also, currently it only supports simple words, but for macro purposes, it could support arbitrary expressions (so for example one could dovar a(return _a, return _a = value):Int
and auto-generate get/set functions for it with a macro!
Add a couple of new features
I love Haxe's minimalistic syntax and clear feature set, but there are things that become more and more common and useful, and that not just short lambdas, but also this:
- Integrated async/await syntax similar to C#, ES7 and Python 3.5, translating functions in a reentrant state machines. I think it was implemented to some extent with macros, but this should really be a core feature of the modern language.
- Destructurization assignments, similar to ES6, CoffeeScript and (to some extent) Python and Ocaml, e.g.
var {field1, field2} = someObject
. This leads us to tuples - a really great construct for returning multiple values, and it can be implemented quite efficiently (at least more efficient than the current alternative: anon structures).
Improve IDE services
With Haxe 3.3 we greatly improved IDE support, but there's still work to be done:
- better structured JSON output for e.g. type info: for example, parsing function types is a HUGE pain (we already have this in the works)
- unicode-aware lexing. Currently haxe reports positions in byte offsets which screws thing over when you use two bytes long or longer characters such as cyrillic or CJK in e.g. comments or strings: as a result, haxe simply reports wrong positions, so I think it's fair to require sources to be in UTF-8 in year 2016
- some way to process the whole project, not just current display file, this is required for functionality like "find references", "rename" or "auto-import" to work right
Infrastructure
Besides Haxe language, compiler and the standard library, there's a lot of work to be done regarding Haxe infrastructure, such as:
- Standard way to do haxe projects. We need something like
package.json
file from the JS world. Haxelib'shaxelib.json
file could evolve to be a generic project file. It could define build and test rules, specify per-project metadata and defines in a structured way, so IDEs could work with that for auto-completion and what not, etc. Maybe we should move even away from the "library" term and use something like "package" or think of some special word (like gem,egg,crate,etc). - All Haxe-related servers should support HTTPS (it's 2016, yay!)
- Haxe and haxelib projects should be on CDN, so people that are far from EU don't suffer low download speeds.
- Haxelib server should provide RESTful APIs for easy integration (badges, statistics, social, bounty, whatever services)
- Contribution guidelines, formal extension proposal procedure (this is something that's already being worked on).
- Official Haxe style guide (similar to Python's PEP8, and an official tool to format Haxe code.
Conclusion
So this is what I'd like Haxe to be, while there are a lot of stuff I described here, it's mostly about quality of life improvements and polishing, not radically reimplementing the whole thing. And if at least a third of this will be implemented someday, Haxe will be even further ahead of everyone and I'll be a much happier person :)