25 ms·
My experience rewriting Enjarify in Rust
- tomjakubowski 10y ago> If you want to be able to refer to the contents of the enum, have named fields, or call methods, you need to create a separate struct definition. Not so! An enum variant may contain named fields. From The Book, https://doc.rust-lang.org/book/enums.html https://doc.rust-lang.org/book/enums.html : enum Message { Quit, ChangeColor(i32, i32, i32), Move { x: i32, y: i32 }, Write(String), }
- the_duke 10y agoI agree with him though that enum variants not being distinct types is a hassle. I think there's an RFC for making this possible.
- lmm 10y agoIt's by design AIUI; certainly it's often what you want (I won't claim "always", but probably more often than actually wanting the distinct subtypes).
- gamegoblin 10y agoEven Haskell needs an explicit language extension flag to make this happen (-XDataKinds I believe). Consider this use case data Pointer = NullPointer | NonNullPointer Int And I want a function that only accepts non-null pointers: dereference :: NonNullPointer -> a To do that and maintain my Pointer type, I'd have to do something like: data NonNullPointer = NonNullPointer_ Int data Pointer = NullPointer | NonNullPointer NonNullPointer -- ^ The namespace of constructors and types is distinct, -- so this is fine and is a constructor of Pointer that -- contains a NonNullPointer, which only -- has one constructor, NonNullPointer_ (note the _) I believe -XDataKinds does something like this behind the scenes, but someone better than I should verify. I just use the above technique rather than questionable language extensions.
- dllthomas 10y agoDataKinds lets you use NullPointer and all the various NotNullPointer values as types, but they are uninhabited. It doesn't (obviously) let you restrict a parameter to values using a particular constructor of a sum type.
- gamegoblin 10y agoJust looked it up and it was GADTs I was thinking of that would allow me to do something like that.
- dllthomas 10y agoAh, yes.
- saosebastiao 10y agoThis is one of my last remaining nitpicks with Rust as a language. In Scala, sum types are a form of sub-type polymorphism, where each variant is its own distinct type and can be used as such. To get similar behavior in Rust, you end up having to wrap structs in the variant like this: struct Foo_ enum Bar { Foo(Foo_) } It works, but it is extremely annoying.
- the_duke 10y agoGood write up. I can agree with him on a couple of points. I've found Rust code to become terribly verbose and unreadable for certain tasks. You have to be careful to not end up with messy and hard to read code. Lifetimes of course make it even worse. Some common patterns are hard / awkward to implement. The stdlib is (intentionally) very small, and throwing together various crates adds a considerable maintenance overhead. Overall I find Rust really promising though. It might need a few more years to mature. I totally agree on Go: I intially really loved it and used it all the time. The more code, and especially the more reusable libraries I wrote, I started hating it more and more, to the point where I only touch Go if I have to, or for small, one-off, self contained projects that need a bit more perf than Python or where Haskell is not appropriate (team, problem space). The only thing that's a plus for go is it's dead-easy concurrency.
- cm3 10y ago> The only thing that's a plus for go is it's dead-easy concurrency. Since you mention Haskell, I would like to say that Haskell's concurrency support is more diverse and at least as easy as Go's.
- masklinn 10y ago> I would like to say that Haskell's concurrency support is more diverse and at least as easy as Go's. More diverse is easy, Go is opinionated about its concurrency. "At least as easy" is a flaming lie. The diversity alone makes it impossible but beyond that: * when you look for concurrent go you're introduced to 3 constructs (`go`, channels and `select`) and you're off to the race having barely learned the language * when you look for concurrent haskell you're directed towards the corresponding paper, "tackling the awkward squad" and a world of Async, MVar, ThreadId, STM and various types of Chan, and at that point you still can't write a line of concurrent haskell Like the_duke I don't enjoy Go, but with respect to dead-easy concurrency the only language that's in the same ballpark is Erlang (and it's similarly boiled down to a complete lack of diversity — though a different model than Go's — and three basic constructs: `spawn`, `receive` and `!`).
- 10y ago
- steveklabnik 10y agoI'm always glad to get feedback, we're specifically going to focus on ergonomics and smoothing rough edges this year, so this kind of thing is invaluable. There's some good discussion on the Rust subreddit: https://www.reddit.com/r/rust/comments/53ft4m/my_experience_rewriting_enjarify_in_rust/ https://www.reddit.com/r/rust/comments/53ft4m/my_experience_...
- cm3 10y agoOff-topic, but since you're here, let me ask: where can I track the progress on rustup support for musl-based distros where musl is the host (void linux, alpine linux) and FreeBSD? I got everything but Rust working nicely on void linux, and it's the only thing holding me back right now. Since Docker defaults to alpine linux, the reach of such support will be wider than one might initially think.
- steveklabnik 10y agoFor void: https://github.com/voidlinux/void-packages/issues/4570 https://github.com/voidlinux/void-packages/issues/4570 And alpine: http://pkgs.alpinelinux.org/packages?name=rust*&branch=&repo=&arch=&maintainer= http://pkgs.alpinelinux.org/packages?name=rust*&branch=&repo... https://github.com/rust-lang/rust/issues/31322#issuecomment-247818983 https://github.com/rust-lang/rust/issues/31322#issuecomment-... is the latest news on the subject. It's not impossible, but we're not sure _how_ we want to make it easy. The real issue is the bootstrapping, my understanding is that cross-compiling a musl compiler from a gnu compiler does work today, which is how those packages were made.
- cm3 10y agoThanks for the pointers. Yeah, after you've bootstrapped once, you have a version to bootstrap another, especially since the new requirements to not depend on a nightly snapshot. rustup should be able to provide images that way which work on both alpine and void. The default would be a dynamically linked against musl rustup image which may still expose musl-static as a target just like it does on glibc hosts. I wouldn't complicate matters as a first step with questions of whether a musl image should be statically linked.
- Fede_V 10y agoThis was exceptionally well written, and it closely mirrors my experience as a python programmer slowly moving into Rust. Rust is awesome, but there are a few rough corners where you end up having to write really un-ergonomic code.
- blub 10y agoAfter reading this article my conclusion is that Rust is some kind of static-typed Perl with a focus on memory safety. The syntax is horrid. steveklabnik asked me once why I thought Rust is more complex than C++. Well, if one takes a look at any of the Rust snippets in this article without being deeply disturbed by the @'s the .'s, &'s and *'s, then we have a completely different idea about what it means to build a user-friendly and ergonomic programming language. Luckily I don't have to pick between Rust and Go, but if I had to I would just stick to Python and use type annotations after reading this.
- steveklabnik 10y agoIn a systems language, it's important to know if you're passing around things by value or reference. We follow the Python maxim here: explicit is better than implicit. This means &s to indicate where something is passed by a pointer, and * for dereferencing. This is the same as C++, we just do less magic coercions. We also tried to not make up too much syntax, and stick to "curly braces and semicolons" for most things. Even lifetime syntax isn't new, though OCaml uses it for a very different purpose than we do. (There also aren't any @s in there, unless I missed something? And . is the same as in any language: for method calls, and we made it _simpler_ than C or C++ here, by having . instead of . and ->.) I agree that you can make a language without many syntactical constructs, but Rust has other goals as well. Language design is hard! There's tons of tension between various choices.
- pjmlp 10y ago> This means &s to indicate where something is passed by a pointer, Having had a strong background doing system programming in Wirth based languages, this was something that I never liked in C, and was quite happy that C++ followed the same path as Algol derivatives.
- p0nce 10y ago> Besides, when nearly every call requires a cast, people will just automatically add them to shut the compiler up, defeating the purpose. That's why there is little reason to "fix" C integer promotion rules in the first place (apart from unsigned).
- mmargerum 10y agoReally interesting write up. I'd love for you to port to swift and gives us your thoughts! :)
- FraaJad 10y agoI wish someone would do this in nim and compare the results. My wishful thinking is that nim would come in at the same number of lines as Python and very close to Rust's performance.
- agentgt 10y agoI was thinking the same thing with OCaml. I wrote in OCaml years ago and I still remember how incredibly terse the language is/was. You can accomplish so much with very few lines of code (with the minor exception of the whole reduplicate signatures and way too many artifacts (mli, cmi, ml, etc)). It also compiles much faster than Rust (I'm not sure about Go but since Go doesn't have that sophisticated type system it isn't really fair). I have to say Rust got fairly hard to read and think about writing code with lifetimes when using closures. I couldn't decide at times whether to just use a trait with some cells or get the closure stuff working. This was in part because of some bugs (about 1.5 years ago) and the fact that their are 4 types function things. It is also probably because I haven't programmed in anything analogous that has lifetimes (I haven't programmed in C++ in more than 1.5 decades).
- spion 10y agoThere is the Python -> OCaml story for 0install: http://roscidus.com/blog/blog/2014/06/06/python-to-ocaml-retrospective/ http://roscidus.com/blog/blog/2014/06/06/python-to-ocaml-ret... This article in particular tackles polymorphic variants http://roscidus.com/blog/blog/2014/02/13/ocaml-what-you-gain/ http://roscidus.com/blog/blog/2014/02/13/ocaml-what-you-gain... which solve one of the issues that the author had with Rust (enum subsets)
- agentgt 10y agoSort of tangental but oone thing I have always appreciated about the Python community and Guido is the flexibility and open mindedness in adding features to the language from other languages. I can't remember where I heard/saw it (it was video iirc) but Guido had pointed out there is real value to having static type analysis to a language. While Python does now have type annotations (pep 484) that are more powerful than Golang (generics) they currently aren't checked. I wouldn't be surprised if future Pythons start readily using these type annotations. At the same time I wouldn't be surprised if Golang never has generic (just my opinion).
- catnaroek 10y agoYou can convert an `Option` into a `Result` and then use the `try!` macro, all in a single line: http://stackoverflow.com/a/37890739/46571 http://stackoverflow.com/a/37890739/46571
- Thaxll 10y agoRust syntax is horrible compare to Python / Go, I don't see how you could give an advice to someone that do Python to use Rust, you lose GC and add a great layer of complexity / learning curve. No thanks. Seriously when I see that: struct IRBlock<'b, 'a: 'b> { pool: &'b mut (ConstantPool<'a> + 'a), // other fields omitted }
- hokkos 10y agoGC is not a feature in all cases, and without GC you must manually handle allocation and deallocation in some cases, C or C++ let you free of lifetime annotations at the cost of crashes, Swift force you to use counted pointers and Rust force you in a semantic that forbid errors at the cost of some lifetime allocation that you consider ugly. But it is still shorter than copy pasted Go code to simulate generics, and multiple "err, res" that stains the code.
- Thaxll 10y agoMy point is a lot of people use Python because it's a simple and powerful language, Rust is not a simple language at all. And the performance it brings is not enough to make the decision to switch language in most cases.
- seangrogg 10y agoIt's not about "switching" languages - it's about making sure the languages you do use solve the problems you care about. Honestly, nobody cares what language you use as an individual other than perhaps your coworkers.
- kbenson 10y agoI'm not sure what you're arguing. The article didn't advise people to switch from Python to Rust. It simply gave information that people that are considering it. The last paragraph even echoes some of your sentiment. > And the performance it brings is not enough to make the decision to switch language in most cases. That's assuming a lot. Nearly 10x the speed is extremely useful for some people. Presumably if you are rewriting your Python code in Rust or Go, you've already identified performance as a big reason to do so, and that gain would be extremely useful.
- Roboprog 10y agoIt's a shame there aren't more "Modula" derived modern languages, rather than trying to force C into being a higher level language. Java, especially at the 1.1 mark, felt like some kind of crippled version of Borland's Pascal/Delphi + a UCSD P-system VM (dressed up to look like C++). Microsoft for C# hired the language designer from Borland. The Go team includes a Uni of Zurich guy, and at least decided to use a declaration syntax (when variable types aren't inferred) more like Pascal. Start with a language that wasn't a shiv with a broken handle in the first place to build applications. It's a shame Eiffel never took off instead of the wretched C++, no, this time for sure, Java... (not, that's not it, either - lather, rinse, repeat) lineage. (C was vastly preferable to assembly in the late 80s / early 90s, but it's time to let it go, and its syntax/semantics, people) Irony: I like the unix philosophy of composing processes in a functional pipeline, which is totally lost in the era of monolithic java crud, but that is another huge tangent. RANT ENDS.
- Hemospectrum 10y agoThe Rust community is pretty good at turning specific complaints into actionable proposals. Could you perhaps be more specific about what nice things in Modula/Delphi/Eiffel are missing from other languages, or about what might be different if Go or Rust borrowed more of their influence?
- Roboprog 10y agoThanks for the response, it was just a rant. I suspect the Rust community and I simply have irreconcilable differences. They want a better C or C++, and like special character ditties such as &, *, <_> (whatever that does), and I would rather have short keywords in some places. For example, declaring a parameter with "var" in a function heading means it is a reference, instead of a copy. However, there is no dereferencing syntax, you simply use it as if it were a local "auto"/stack type variable (which also cannot be a null, so no checks are required - which Rust probably takes care of as well if you ask nicely), and there is nothing special for the caller to do, unless the caller has a pointer that needs to be checked and then dereferenced in the call. I also miss reasonable "set" operations, even if the sets were just bit vectors on short enumerated types (enums or short sub-ranges of other discrete values). Maybe Rust has sane set operations, but Java's collections operations are a bit off: mutating "add-all" vs union producing a new set, and so on. Eiffel's pre/post-condition and class invariant special assertions are nice, as well.
- alexnewman 10y agoPlenty of ways to .orthat for options. The author should checkout the option type in detail
- alexnewman 10y agoPlenty of ways to .orthat for options. The author should checkout the option type in detail
- tombert 10y agoI'm curious what the performance would be if it were ported to Haskell or OCaml. It almost certainly would be slower than Rust, but I think some benchmarks would definitely be interesting when comparing those languages to Go.