Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

As I said, the primary reason I wanted macros was for the DSLs they make possible, not their use in application code. For example when I’m working on a Phoenix app, I very rarely write a macro, but I get a great deal of benefit from Elixir them since they make Phoenix’s router DSL, Ecto’s database query syntax and the standard testing DSLs possible.

I disagree that "pattern matching is "really just a more concise switch/case syntax" and use it regularly in function heads and in parsing nested data structures.

More importantly, I reject the premise that the four items you mentioned are the only things really lacking or even that the problem with TS was a lack of features as opposed to its bad features, superfluous features and poor design decisions. For example, I'm not a fan of any of the following:

- loose typing

- multiple ways to declare variables, with different scoping rules

- multiple ways to declare functions, with different treatment of "this"

- the ability of code in any module anywhere in the system to affect code in the module you're looking at without leaving any evidence of this in the module you're looking at

- the ability of functions to alter parameters they're called with

- the sort function in the standard library being destructive by using the above

- etc...

That said, JS/TS really is missing some important things that didn't make your list:

- a good concurrency model

- macros

- compile time guarantees about references

- list comprehensions (actually minor)

- a sufficient standard library

- etc...



Fwiw, the function syntax in Typescript/Javascript is generally expressive enough to use as a basis for DSLs, and not needing to use macros for this also has a lot of benefits. I'm a big fan of Rust, but I find often library authors overuse custom syntax in macros when just writing functions would have been easier, just as expressive, and much simpler to integrate with an IDE. Where macros do exist in Javascript-land, they tend to be either to implement upcoming features, or as optimisation tools (e.g. converting CSS-in-JS expressions at build-time rather than run-time). The one exception here is probably JSX, but even there lots of people prefer to use function calls instead.

But for things like testing blocks, configuration, HTML/CSS generation, etc, it's generally enough to use the language by itself.


If JavaScript is “expressive enough to use as a basis for DSLs”, why do you suppose it is that various explicit attempts to recreate RoR in JS, going way back to SailsJS have failed to recreate its router DSL or even similarly terse models or controllers?

Of course not everyone wants a Rails-inspired MVC framework experience, but why do you figure even those who did couldn’t achieve the same level of syntactic sugar?

(I know Ruby doesn’t have macros either, but it does have enough expressiveness in a few other ways to do some things Python and even JS can’t)


It's interesting that you mention Python, because obviously the RoR equivalent there is Django which leaves something to be desired when it comes to DSLs and expressive APIs. Symphony and Laravel also come to mind here, and I guess Spring in the Java world. I think it's difficult to argue that the creation of a major web framework hinges on being able to express things in a nice DSL.

Rather, I think the truth is that server-side Javascript tends to be used in a different way to Ruby - generally Node projects that I've worked on are much smaller (and often coupled with other similarly-sized services), and are often just minimal APIs designed to act as a middleman between a database and a front-end application. It's not an issue with missing expressivity, but rather a tendency not to need (or at least, not to want) the full-featured powerhouse that is RoR.


These comments are getting a little large, so let me break it into topics:

# DSLs

I'm not familiar with a Phoenix development workflow, but judging by what you've written already, it seems that DSLs are the main sticking point for you.

If I understand correctly, you want to use them to minimise the amount of code you need to write to and/or to guide the project to follow a specific pattern.

I already see this being used in the js/ts sphere:

- NestJS uses decorators for routing and to make the MVC pattern more terse: https://stackblitz.com/edit/nestjs-typescript-starter-pcysqn... - AdonisJS uses decorators for its ORM: https://docs.adonisjs.com/reference/orm/decorators#column

---------------------

# Pattern matching

Can you give an example of what you mean by "use it regularly in function heads and in parsing nested data structures" in regards to pattern matching?

I'm under the impression that it's just a shorthand switch/case that uses filters as conditions.

The current ecmascript proposal for pattern matching (which would end up in js and ts if passed) seems to be inspired in part by Elixir/Erlang.

---------------------

# Features that you're not a fan of

One of the things that makes TS so interesting is that it's a broad language. It doesn't impose a way of development for you.

You can start a project based on how you know how to develop.

- If you already know about functions and typing systems then you can start programming right away.

- If you only understand 90's style OOP then you can start programming right away

Developers should have the option to define the programming styles of the project that they create.

But to go through your list:

> loose typing

I don't see this as a negative.

Those that want strict typing use strict typing, those that want loose typing use loose typing.

> multiple ways to declare variables, with different scoping rules

The `var` keyword is only there for backwards compatibility.

But, if you do try to use it in a new project, you'll be alerted immediately by eslint and you can change it to `let` or `const` depending on your intention.

> multiple ways to declare functions, with different treatment of "this"

All this comes down to is if you want to do OOP (function keyword), or functional (arrow functions).

Use the one that suits you best.

>the ability of code in any module anywhere in the system to affect code in the module you're looking at without leaving any evidence of this in the module you're looking at

What do you mean by this? It sounds like you're describing side effects in general, and nothing to do with modules.

> the ability of functions to alter parameters they're called with

What do you mean by this?

When you pass by reference, you get the same reference. When you pass by value, you get a copy of the value.

If you want to alter the original source of something directly, you pass by reference.

If you want a temporary copy of a value, you just pass the primitive value and you'll get your own copy of it scoped to a function. Now you can make whatever changes you want to it, and when you're happy you can return the final value. This has the added benefit of the outer value not being stuck in a half-changed state if the function throws in the middle of its execution before the changes to the value were finished.

> the sort function in the standard library being destructive by using the above

I'm not sure what you mean by this. This is just pass-by-reference vs pass-by-value again.

---------------------

# Features that you think are missing from JS/TS

> a good concurrency model

JS/TS already has an event loop, async/await functions, pull-style generators, and threads.

One of the things I suggested in my previous comment (but marked as needing further investigation) was an effects system. They can be used to make so-called "colorblind" functions which can be valuable for some async workflows.

> macros

I don't see how these are different from decorators. Unless maybe you're talking about compile-time macros, in which case that's more in line with metaprogramming and things like extending the language with your own (re)compilers like babel.

> compile time guarantees about references

Isn't this what `readonyl`, `as const` and the `satisfies` operator already achieve in TS?

> list comprehensions (actually minor)

Yeah, this is minor. Just syntactic sugar, nothing more to say here.

> a sufficient standard library

Yeah, a lot of early weirdness was caused by not having a standard library. But now we have things like lodash and deno's std.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: