Idea: consider change features/keywords like 'fun" and 'and' to something more understandable. ALSO arbitrary syntax transformations for different flavors?


#1

‘fun’ is a commonly used keyword to actually declare a function (e.g. Kotlin). Not sure what would be a better keyword but something that makes it clear that it’s related to the ‘switch’ keyword.

the ‘and’ keyword is something I still don’t quite understand. Is it actually necessary?

ALSO:

Would it be possible and/or desirable to have some kind of project configuration (kind of like eslint rules) that allows for different syntax rules to be configured? I believe the reality is that different groups of people have, and in the future will still have, different preferences.

Would it be ok if different flavors of ResonML emerged, maybe one catering to OCaml developers, one catering to JS develoers, etc. If it would be as simple as something like setting eslint rules or babel presets, and then your whole project would be reformatted according to these rules – I think that would be pretty sweet.


#2

I believe this is done currently by using the OCaml syntax or using the Reason syntax. Both are supported by all relevant toolchains.


#3

What do you propose? match? Might be confusing for the OCaml crowd. I don’t know, fun got familiar pretty quickly for me.

Reason has actually done away with OCaml’s in, for instance. As for and, how do you propose to describe [mutually] recursive values/types?

It would also be a great deal of work and complexity for BuckleScript/Reason maintainers, and worse yet, wouldn’t make the Reason users’ lives any simpler. Between PPXes, FP indirection, custom operators and whatnot, Reason is hard as it is without having to sweat over formatting configs or getting lost every time you open somebody else’s code. Unified code formatting is a feature, not a bug.


#4

I have no idea, ideally no keyword would be necessary but I guess other cryptic tokens is worse.

To play devil’s advocate, why are mutually recursive values/types necessary? I’ve been programming professionally for 20 years and I’ve never needed them, so why do I suddenly need them? And why can’t the compiler figure out what values/types depend on each other within a given scope?

To be clear, I’m not talking about formatting, I’m talking about syntax. For example, suppose for some reason my team prefers reading func(x, y) instead of (x,y) => (because arrow functions are ugly to some programmers). This would allow us to make that decision instead of having it fixed.

It might not be a great idea, because it could cause fragmentation and confusion initially, but it would be an innovative feature.

My feeling though, thinking about it more, is that this would be better as UI layer over the textual syntax. I’m envisioning an editor that can be customized with plugins. My feeling is perhaps around 2020 we are reaching the limits of innovation of purely text-based languages.


#5

Note: the reason I thought of this is because I know Reason already is a new syntax layer over OCaml, which made me think (perhaps erroneously) that further transformations would be pretty trivial.


#6

To play God’s advocate, I don’t know much about compilers, but maybe hoisting adds a lot of complexity for a compiler and disallows certain optimizations. Also, I guess it wouldn’t play well with OCaml’s shadowing logic.

Better visualisations and navigation would be nice. I mean, IDEs have module/class structure trees, graphs, go to definition/implementation and whatnot, but I believe we could do better. But I think it would take a lot of research and UX/DX expertise to do right. Then we would know what should be changed in the language services.


#7

You’ve never made a, say, Linked List type before?


#8

It is used in mutually recursive definitions (as mentioned above) and also in a couple of other places like multiple type substitutions:

module type T = {
  type t1;
  type t2;
  
  let foo: t1 => t2;
};

module IntT: T with type t1 = int and type t2 = int = {
  type t1 = int;
  type t2 = int;
  
  let foo = t1 => t1;
};

Now, one could make the argument that Reason should change this syntax to something like:

module IntT: T with type t1 = int, type t2 = int = {...};

But given that and is also used for a conceptually similar thing (mutually recursive definitions or in other words deifinitions where all parts of the definition are considered part of the whole), I feel like the syntax actually maps to the semantics in this case and it would be difficult to justify changing it.


#9

It also translates rather nicely to parallel bindings with ppx_let.

let%bind foo = getFoo();
let%bind bar = getBar();
Js.log2(foo, bar);

// equivalent to

getFoo().then(
  foo => getBar().then(
    bar => console.log(foo,bar)));

// ---------

let%bind foo = getFoo()
     and bar = getBar();
Js.log2(foo, bar);
// equivalent to

Promise.all([getFoo(), getBar()])
  .then(([foo, bar]) => console.log(foo, bar));