Hacker News new | past | comments | ask | show | jobs | submit login
Hecto: Build your own text editor in Rust (philippflenker.com)
154 points by lukastyrychtr 10 months ago | hide | past | favorite | 38 comments

> Why? I have always thought that every software engineer needs to have more than superficial knowledge of at least two programming languages. However, I have to admit, that in the past few years, my knowledge in pretty much everything except JavaScript has started to fade.

Slightly OT, but it's interesting to me how common this story seems to be. It's basically my story with Rust too. In many ways Rust is the polar opposite of JS: low-level memory model, high-performance, meticulous and cohesive language design, strict-typing-first. But in terms of its culture and ecosystem there's a lot of overlap: a vibrant package ecosystem that you're encouraged to hook into, trivial cross-platform-targeting, embrace of creativity, and a closeness to the web that spans everything from first-class (de)serialization support to first-class WASM support (unsurprising given its origins at Mozilla).

My theory is that there's a whole bunch of us who use JS at work and are specifically looking for the exact opposite in our hobby projects, not because we hate JS but because we want a palette cleanser/to keep our knowledge broad, and that many of us are turning to Rust, and that this may be a driving force in the way the Rust ecosystem is evolving.

Edit: I have to wonder if there's a similar phenomenon going on with Clojure. It too is very popular with hobbyists, and less popular with companies, and positioned as both adjacent to (in terms of ecosystem and amenities) and directly opposite from (in terms of semantics and developer experience) an extremely popular enterprise language - Java - which many people use every day at work and have a love-hate relationship with.

I think Raku ( https://raku.org/ )[1] is a facinating "hobby" language - taking a lot of the Ruby "optimised for joy" stuff to a whole different place (leaving a lot of the ruby simplicity and going for sheer raw power and brevity, at the expense of the learning curve and density).

It's really interesting to check out if you want something really powerful and able to hack stuff up quickly / differently.

And all the perl languages definitely have some of that "we code in C for boring stuff, but need something fun and powerful for what we enjoy" ethic.

There was a blog post at one point somewhere talking about a supposed divide between "East coast" and "West coast" languages, which I can't find right now...

[1] It was called "Perl 6" once upon a time...

The decision took a month ago to focus on Raku as my hobby language and learning since then so much about programming and different ways to do stuff is refreshing. The language is well thought and if some stuffs are note yet possible (like using grammars for binary data for example). I think the last time, I felt that a language is providing you a new world to play with it is when I discovered Racket.

I used Python and R mostly in work environment and always wished to leverage Julia. The overlaps between Julia and Raku made me realize how to do some stuff and have a better grasp on some Julia capabilities that where perceived as fuzzy concepts. Multi-dispatch for example but also the parallel between NativeCall in Raku and the C API access in Julia. Even if we fall more in the two languages fallacy with it, it is crazy to see how it is easy to provides binding for C, C++, Fortran or Rust libraries to Raku.

Besides that Raku is a joyful/fun language that does not block you if you want to do serious stuffs with it. For that did not come form nowhere. At each FOSDEM edition, I was always peaking for some talks in the Scheme/Raku/Perl room and each time enjoying the talks and the possibilities discovered. I was there in 2015 at FOSDEM when Larry Wall made the official announcement for Perl6, I saw a few talks by Andrew Shitov and others.

In these times where you find a load of articles "learn foo in X minutes", I really like to read more about Raku with the feeling I am "learning Raku for a lifetime".


I really think that the parallel between what Raku and Julia have got right from the syntax and the integration of unicode, the lisp-ish nature, etc. Julia even got a few more think as having a AST and macro around it (coming in Raku when the RakuAST branch will lend later this year), using GMP binding for arbitrary arithmetic (maybe coming to Raku/do soon).

Raku like Julia have this Lisp feeling where everything is possible to reproduce due to the flexibility of their inner working.

Actually, I've been working with getting grammars for binary data working in Raku. Development paused though when I had some trouble working with slangs.

I've gotten a bit better with them since then, but now I'm holding off for RakuAST, else I'd probably be rewriting a large amount of code for nothing (or have some major performance hits). You can see the proposal at https://gist.github.com/alabamenhu/2fec7a8f51a24091dc1b104a2... and a very early implementation at https://github.com/alabamenhu/BinexObjex

Definitely read over the proposal and comments, as my work with binary formats is a drop the bucket of ways to work with them, and I'm always interested in hearing how others would need/use such a feature.

> "East coast" and "West coast" languages

I don't know about the blog but afaik the notion arose from "Worse is better".[0]

[0] https://en.wikipedia.org/wiki/Worse_is_better

> bunch of us who use JS at work and are specifically looking for the exact opposite in our hobby projects

I use Rust at work, and JS only in hobby projects :)

There is something "opposite" about these languages, but I think both coexist because there's very little overlap in their use-cases. You use Rust where JS can't be used (multicore, high-performance, or low-level native code), and use JS where Rust would be overkill (small webby things).

Just picking a nit, but it's not multi-core that JS can't be used; Node has some solutions for leveraging all your cores (multiple node processes, basically. PM2 and its ilk). It's specifically CPU bound problems, where the benefits of JS' concurrency model can't shine.

Picking a further nit: the key difference is that most other languages can share memory directly between threads, whereas JS can only pass messages between threads (which requires copying data, and usually serialization/deserialization)

Workers have "transferable" objects that in theory avoid copies, but still there's a world of difference between coarse-grained message-passing style, and fine-grained data parallelism you can get from something like rayon.

JS "can" do a lot of things if you know how, and cleverly implement and optimize the code, but it's a Turing Tarpit. You wouldn't implement a video codec in JS. You could, but it's not the best language for it.

I wonder if Unity-like game dev projects could use Rust as a low-level language and JS for all scripting?

>its culture and ecosystem there's a lot of overlap

It's just "being more modern than the 1980s". Rust's the first low level lang to be able to say that.

D came before Rust and was and is pretty "modern".

Ultimately this depends on what modern means to you, but I'm guessing you can't write the "Tiny RPN Calculator" from the D homepage as concisely[1] - i.e. My point is that Rust isn't the only language that isn't C++

[1]: dlang.org - you can play with the exact code here https://run.dlang.io/is/FiWrHF

I wrote it a few years ago (not long after I learnt the language, actually), I wasn't even trying to golf, it came almost straight away just from reading the docs. Note the use of static foreach to generate the switch cases for fun and profit.

No memory safety in D though. That's a pretty big deal for those of us coming from high-level languages who are not used to dealing with such issues.

I can deal with a fussy compiler that makes me write code in a certain way. But a langauge that compiles fine then segfaults or worse at runtime is far more trouble than it's worth (and requires me to make a big upfront time investment before I can start writing production ready code)

> No memory safety in D though.

Not true. Even ignoring the GC we have compiler checked semantics for an increasingly large subset of features, and the language has had ways of managing code that is safe, unsafe, or trusted for years and years now.

As a newly minted employee of the D foundation, I am aiming to work to expand the memory safety features D has.

Is there a way to make it safe-by-default, such that I can't accidentally stray beyond what the compiler can prove safe?

There was a proposal to do just that in our DIP (D improvement proposal) pipeline that nearly made it but it (probably correctly) received enormous backlash.

However, if you use @safe (that's the attribute) the compiler will hard-error if you call any code that you use that isn't explicitly also either @safe or @trusted.

There is also DIP1000 and DIP1021 which both loosen @safe semantics to perform semantic analysis to allow safe memory behaviour (A small borrow checker in effect, this will hopefully be bigger soon).

Try accessing a struct property that isn't in the declaration, or accessing a value after it has been freed (out of scope). You'll get a compile error.

D has lots of memory safety features. It is not the same set of features as Rust. It's wildly incorrect to suggest that Rust has a monopoly on memory safety.

Haha. True! I knew about D, but I forgot about it[0]. (I also know extremely little about it.) ;w; I feel bad.

That code is as beautiful as it is incomprehensible.

0: https://youtu.be/_P5BOietpDY

I agree. The D program is cool, but pretty cryptic. A simple Rust version [0] is only 21 lines yet much more readable in my opinion. I'd take readability over a couple less loc anyday.

[0]: https://play.rust-lang.org/?version=stable&mode=debug&editio...

The `op.parse()` at line 7 was a little hard to understand for me at the beginning. Only a few seconds after, I understood it was `op.parse::<f64>()` with the type parameter inferred from the type of `stack`, but I think it's easier to understand with the explicit type annotation (the turbofish) than without it.

You miss the point of the original one. When I wrote it the idea was that it is functionally pure and guaranteed to be such by the compiler (the annotation was removed because readln is not pure for obvious reasons).

Most uses of loops break down to map, fold, or similar being able to use them cleanly can avoid a lot of bugs and API plasticity.

There's nothing stopping you from doing a functional style in Rust, neither: https://play.rust-lang.org/?version=stable&mode=debug&editio...

There is a function on nightly that would make line 16 a little nicer, but oh well.

Ada says Hi!

Ada was designed from 77 to 83.

First standard was released in 1983, later updated in 1995, 2012, 2014, with an update revision coming up.

Has the ability to specificy formal proofs in the type system (SPARK).

Which basically beats the point of Rust being the only modern language happening post 1980.

Ada was just one possible example, SIGPLAN archive has a couple more to pull from.

That explains some things like the packages and the tooling, but not everything

I never heard of java devs playing around with java, IDEs et al. in their free time either. I'm sure they exist, but sounds entirely foreign (hello Apache!).

I’ve found that Kotlin has changed that, at least for me. I enjoy playing with it even for small projects, something I’ve really never done with Java.

Seconded here, Java/Scala and maybe a bit of Kotlin are used for client projects but personal and play projects I almost always do in Kotlin.

I will wax poetic about Kotlin to any programmer that will listen. To me, it feels like a language created by seasoned Java developers who were tired of the tedious parts of writing Java.

Plenty of us, how do expect Java open source projects get born?

Or Android apps for that matter.

Doing one yourself is fun. MicroEmacs drifted around NNTP in the 80s, and I snagged a copy and began modifying it to taste. I've been using it ever since. The latest version was ported to D:


It's a very easy editor to understand and extend.

I found this to be an extremely valuable tutorial! The step-by-step format using code diffs made everything very clear and easy to follow along. If you're a beginner or intermediate Rust developer, Phillipp's series of tutorials can also be useful as a guide to structure a moderately feature-full codebase in a way that is easy to grok. Great work and I'd love to see a similar series like this on other topics like building a Markdown parser or basic key-value database for example.

Thank you! I enjoyed writing this a lot, but I have to admit that having kilo as the predecessor allowed me to focus exclusively on Rust without having to worry about other things. I hope to find the time to write a different tutorial soon.

Based on the great Kilo tutorial to reimplement a simple text editor in C https://viewsourcecode.org/snaptoken/kilo/

I'll try to allocate time for this.

I did write my own editor in C and it was delightful and it addressed my pet peeve with Emacs: the two wasted lines at the bottom (on small devices every single line matters). However I don't actually use it myself because it's missing too many essential features and it would take too long to write them. Also, cross compiling C for multiple platforms is actually tedious due to silly differences between eg. macOS and Linux.

The holy grail for me is still the editor from BLS Pascal which was a full screen editor in about 2 KiB of Z80 machine code. I'm still not sure how Anders managed so much functionality in so little code, but there's just a few little things I wanted differently (which as having Enter split lines and delete joining them).

This is exactly what I need right now. I’ve always wanted to build an editor (some say every programmer should build an editor at least once?). Starting tomorrow morning!

A nice and fun tutorial. I'd also like to see a text editor example in Rust implemented using a persistent data structure, for better concurrency (e.g. background save) and undo support. Perhaps I should have a go!

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