Live data from Hacker News

High-Level Rust: Getting 80% of the Benefits with 20% of the Pain

hamy.xyz

51–60 of 122 posts

Re: High-Level Rust: Getting 80% of the Benefits with 20% of the Pain

#51
I agree that rust devx is a bit lacking (not much though tbh), and that as the article suggests, structuring your project in a way to ensure invalid states simply cannot be represented is "the way." However, the assessment of other languages limitations seem a bit off to me, or at least I'm not grokking what they're claiming (a "me" problem in that case.)

What does "types in typescript are lies" even mean? Typescript from my experience has a fairly robust typing system with union types etc that many other languages called out lack (java, etc)

Is it a "lie" because it compiles to js? Compiler guarantees still stand regardless of whether you target IR, bare metal CPU instructions, etc. "any" types are definitely a foot gun, sure, but it I wouldn't call ts' type system a "lie" and not explain what that means. The ts language and ecosystem definitely has it warts, but in general those warts aren't the type system.

EDIT: correction, turns out I was fooled by ts lies all along. They allow clear type violations in several cases by design as pointed out elsewhere in this thread. Shame on them I guess. That said I've been using typescript in strict mode heavily for a year and it's good enough. Apparently there are some knarly edge cases hiding around several corners...yikes

Re: High-Level Rust: Getting 80% of the Benefits with 20% of the Pain

#52
post #26
post #8

Earlier quoted context omitted.

Pretty sure by devx they mean something like syntax ergonomics. Because otherwise rust's devx first class (cargo, clippy, crates.io) so kind of a nonstandard definition. I think it's fair to say Java's "syntax ergonomics" are a little below the rest / somewhat manual like rust or C++ by default.

Yeah, but worse than Go?

go's type system is significantly more limited in what it can do for you, as opposed to rust or ts. Limited syntax seems to be one of the overarching design decisions for that language, making it more like C with better concurrency primitives. It can feel a bit limiting at times, but at least they have generics now and you can almost do things like union types by constructing interfaces that mimic them, but it isn't exactly ergonomic.

Re: High-Level Rust: Getting 80% of the Benefits with 20% of the Pain

#53
post #36

Earlier quoted context omitted.

The main problem with TypeScript is the default compiler flags are not safe. I understand having things weak when you’re getting the ecosystem up and running, before you have wide adoption. You don’t want to throw too many red squigglies at early adopters and cause them to give up. But these days the default should not allow any. No implicit any. No explicit any. The stdlib should not use it. JSON.parse() should retu…

Even with strict flags on, there are failures. A trivial example: function mutateArray( arr: (string | number)[] ) { arr.push(1); } const a: string[] = ["one", "two"]; mutateArray(a); a is now a string[] with a number inside

Yikes. I've only been using ts for about a year, I had no idea this was considered a "valid" case. Seems like a type error to me. I wonder how they justify this?

Re: High-Level Rust: Getting 80% of the Benefits with 20% of the Pain

#54
post #50

Earlier quoted context omitted.

Very interesting. I’m shocked the typescript creators built a system with this failure mode. I guess the solution here is to have tsc change the type of “a” after the call to mutateArray, unless the arr argument is marked as readonly. Is there a name for this failure mode?

In TypeScript it's called "bivariance", which sounds very programming language theory like, but is not a term typically used in academic contexts, since it is unsound almost by default. It's described here: https://www.typescriptlang.org/docs/handbook/type-compatibil...

Key sentence in their justification seems to be:

"allowing this enables many common JavaScript patterns"

Honestly at this point they should make a new strict "no js" mode, as the ecosystem likely has reached a tipping point where you can get by without mixing typed and untyped js at compile time. Wonder if targeting wasm directly would help ensure those boundaries are ensured...

Re: High-Level Rust: Getting 80% of the Benefits with 20% of the Pain

#55

Crystal lang deserves a look given the article writer’s preferred language attributes. It has OO paradigms, elegant composability, efficient codegen etc.

I really wish the ruby maintainers had gone with optional inline types like python3 did. Then crystal would simply be a "strict" type mode of ruby. Now we have two basically identical languages with separate communities and libraries. To me it seems... Not ideal.

That said, I laud crystal for doing what ruby would not. It's a great language, but I doubt it'll ever make it to even ruby usage numbers.

Re: High-Level Rust: Getting 80% of the Benefits with 20% of the Pain

#56
post #4

Java have less of a DevEx score than C# is crazy work.

I think devx is being misused in this article a bit. Obviously the tooling for java is second to none, aside from maybe the travesty that is gradle.

What they apparently mean is how "ergonomic"/"expressive" the actual syntax and type systems of those languages are. In that case c# is ahead of java by a decent margin. Luckily java is still evolving, usually by stealing many of the good ideas from other languages like kotlin. But overall those are less language and more runtime features like project looms green threads etc.

Re: High-Level Rust: Getting 80% of the Benefits with 20% of the Pain

#57
post #44

Earlier quoted context omitted.

I think the problem is the union argument type - intuitively we read "array of strings OR numbers", but actually it means "array of strings AND numbers". Probably generics would be more appropriate here, with the type param constrained to string or number. Then tsc would also complain about pushing a number without checking the item type before.

If it's an "array of strings AND numbers", then it should not be allowed to call the function with a string[], because those are different types.

That’s barely scratching the surface.

In TypeScript the following is also valid:

class Something{

    value: Number
}

class SomethingElse{

    value: Number

    foo: String

    bar: SomeOtherThing[]
}

function AddSomething(v: Something)

{

    v.value += 1;
}

var ex = new SomethingElse{

    value: 3,

    foo: “TypeScript is fake types”,

    bar: []
};

AddSomething(ex);

Why does it work? Because in TypeScript as long as you have a “shape” that fits, it’s the “same type.”

Complete and utter insanity to me, to pretend there’s any real type checking, when types are entirely fake and made up.

Re: High-Level Rust: Getting 80% of the Benefits with 20% of the Pain

#58
post #6

I agree that the rust community frowns a little too much on the use of Arc/Cloning/Box. If you use swift, everything is ref counted, why subject yourself to so much pain for marginal gain. Tutorials and books should be more open about that, instead of pushing complex lifetime hacks etc., also show the safe and easy ways. The article gives Java a worse devx rank than Go and I can't agree. Java is at least on par with…

There is a significant chunk of the rust community that encourages the use of Arc, clone and Box outside of the hot path. Perhaps you're just hooked up with the wrong part of the community?

You're likely to get more pushback when creating public crates: you don't know if it's going to be someone else's hot path.

But the internal code for pretty much any major rust shop contains a lot more Arc, Box and clone than external code.

Re: High-Level Rust: Getting 80% of the Benefits with 20% of the Pain

#59

Earlier quoted context omitted.

> I agree that the rust community frowns a little too much on the use of Arc/Cloning/Box As usual, this depends heavily on what you do. I had written a program where Arc reference counting was 25 % of the runtime. All from a single instance as well. I refactored to use borrows and annotated relevant structs with lifetimes. This also enabled additional optimisation where I could also avoid some copies, and in total I…

For the use cases outlined in the OP, a 36% performance gain for an optimization that complex would be considered a waste of time. OP was explicitly not talking about code that cares about the performance of its hot path that much. Most applications spend 90% of their runtime waiting for IO anyway, so optimizations of this scale don't do anything.

> Most applications spend 90% of their runtime waiting for IO anyway, so optimizations of this scale don't do anything.

Again, depends on what you are doing. If you are doing web servers, electron apps or microcontrollers, sure. If you are doing batch computation, games, simulation, anything number crunchy, etc: no. As soon as you are CPU or memory bandwidth bound, optimisation does matter. And if you care about battery usage you also want to go to sleep as soon as possible (so any phone apps for example).

Re: High-Level Rust: Getting 80% of the Benefits with 20% of the Pain

#60
post #44

Earlier quoted context omitted.

I think the problem is the union argument type - intuitively we read "array of strings OR numbers", but actually it means "array of strings AND numbers". Probably generics would be more appropriate here, with the type param constrained to string or number. Then tsc would also complain about pushing a number without checking the item type before.

If it's an "array of strings AND numbers", then it should not be allowed to call the function with a string[], because those are different types.

That would be the sound way to do things, but it's also surprisingly common for arrays for some reason. It also doesn't get checked compile time in Java, although it does throw an exception because the arrays are type-enforced at runtime at least.

This compiles fine:

    class A {}

    class B1 extends A {}
    class B2 extends A {}

    public class MyClass {
        public static void main(String args[]) {
            A[] array = new B1[1];
            array[0] = new B2();
        }
    }
Post reply on HN