News for hackers. Stuff that matters.
Re:Elixir – Why the dot (when calling anonymous functions)? by sbjs on Monday August 14, 2023 @01:19PM (#37123711)
Why not? I can't think of anything off the top of my head that I think is fundamentally broken about TypeScript, or even that I strongly dislike about it.
Re:Elixir – Why the dot (when calling anonymous functions)? by frou_dh on Monday August 14, 2023 @01:41PM (#37124027)
- Too many statements instead of expressions.

- Lacks structural pattern-matching.

- Lacks first-class sum-types (although they can be clumsily encoded as objects with "kind" properties).

These are the sort of things people appreciate in "good" static languages, as opposed to the static languages you alluded to that Python/Ruby/JS/etc were rebelling against in the 2000s.

Re:Elixir – Why the dot (when calling anonymous functions)? by wtetzner on Monday August 14, 2023 @01:52PM (#37124190)
Depending on who you ask, the fact that the type system is unsound could be considered a form of brokenness.
Re:Elixir – Why the dot (when calling anonymous functions)? by LadyCailin on Monday August 14, 2023 @01:38PM (#37123980)
Its type system is apparently Turing complete. That’s a pretty major flaw, imo. Meaning that static analysis isn’t always possible.
Re:Elixir – Why the dot (when calling anonymous functions)? by consilient on Monday August 14, 2023 @06:26PM (#37127552)
Turing complete type systems are extremely common. C#, C++, Java - it's hard to avoid if you have subtyping and generics. In practice it almost never comes up.
Re:Elixir – Why the dot (when calling anonymous functions)? by consilient on Monday August 14, 2023 @06:56PM (#37127832)
A small sample:

The existence of `any`; worse yet, the use of `any` in the standard library.

Mutable arrays are treated as covariant: the classic `cats : Cat[] ; animals: Animal[] = cats; animals.push(dog);` problem.

Methods are both co- and contravariant in their arguments by default, which is comically wrong. Member variables which are functions, meanwhile, are handled correctly.

`readonly` is a lie:

    const test: {readonly a: number } = {a: 0}
    const test2: {a: number} = test
    test2.a = 5
`Record<string, string>` is actually `Record<string, string | undefined>`. There's no way for an interface to specify that it really does return a value at any string index (e.g. for a map with a default value).

`{...object1, ...object2}` is typed as the intersection `typeof object1 & typeof object2`, which is not correct.

    const a: {a: 5} = {a: 5}
    const b: {a: 4} = {a: 4}

    const spread = <L, R>(l: L, r: R): L & R => ({...l, ...r})
    const impossible: never = spread(a, b)
You have to resort to bizarre conditional type hackery to control when unions distribute and when they don't.

You can constrain generics as `<T extends string>foo(t: T) => ...` but not `<string extends T>foo(t: T) => ...`, which makes many functions (e.g. Array.includes) much too strict about what they accept.