Hacker News new | comments | show | ask | jobs | submit login
Why I’m dropping Rust (medium.com)
276 points by posthoctorate 290 days ago | hide | past | web | 158 comments | favorite



The solution linked to in "Go has a suitable answer" isn't relevant, because it doesn't support virtual methods. You can do the same thing described there in Rust by having a base struct, embedding the base struct in any child structs (composition over inheritance), and implementing Deref/DerefMut on the child if you like.

Go has the exact same set of features Rust has here, no more: struct composition or interfaces/traits.

Regarding graphs: The best solution is option 3, using a crate on crates.io (petgraph is the most popular, but rust-forest is fine too). The preferred solution to having multiple types of nodes in the same tree is to use an enum or a trait. (Servo uses a trait for its flow tree, with downcast methods like as_block() if needed.)

I'm puzzled by the contention that the fact that all nodes have to be the same type is a problem with Rust. That's always true in any language. Even in C, you'd have to have your next/previous pointers have some type, or else you couldn't traverse the list!


> The preferred solution to having multiple types of nodes in the same tree is to use an enum

That's not really a great option for a widget library, because it means no custom widgets.


But widgets do have the same type: Widget, which the author already uses as a trait object. I think he was getting confused by mixing &Widget and Rc<RefCell<Widget>>. Just declare a type alias for the latter, use it everywhere, and it should work. You would do the about the same thing in C++, I believe.


In that case, just use Vec<Box<Widget>>, which means "a vector of objects which implement the Widget interface."


Yes, it does. You can use a trait to provide extensibility.


"Regarding graphs: The best solution is option 3, using a crate on crates.io (petgraph is the most popular, but rust-forest is fine too)."

Or, couldn't you have a vec that owns the nodes and use indices instead of pointers? Or use pointers with the lifetime of the vec?


You could, but petgraph does that for you, so your life will be easier if you use petgraph :)


I don't know anything about Rust itself but I find it amusing that the author thought that six months should have been more than enough time for the community to agree on and implement a nontrivial change in how the language works.


Yeah. As a non-Rust developer I was reading the post with some interest and a little sympathy until I saw his timeline.

"Right, so they've been working on this potential change since 2016, and...wait. 2016?!"

If he'd said 2014 or earlier, I'd consider him to have a point. 2015 is asking for a bit too much, but I can still see his frustration; I'd call that a wash. But 2016? It destroyed his credibility with me, because it's clear he has no idea what he's talking about when it comes to developing a programming language.

I know that sounds harsh but...man. He's leaving Rust because they're taking more than six months to implement a massive change to a core language mechanic? Have fun working with absolutely any other language ever.


> Traits as a concept have been part of the language for numerous years. It's currently September 2016.

Reads to me like he is disappointed that they didn't start the process sooner and have just recently started to discuss a solution.


Yeah, most of criticisms I've seen of Rust (ergonomic issues, benchmarks, compile time, even integer overflow) will be dealt with in time. 1.0 means that Rust is stable but lacking features.


Exactly. If you read that thread you can see there's careful and ongoing technical discussion of the details necessary to implement the feature.

It hasn't languished, it's not just a bunch of +1s met with developer silence. What precisely is the author expecting the Rust team to do better on here?


He expects them to say "fuck it, we'll do it live"


Add to that, that the author is an Electrical Engineer.

Not that it's a bad thing but if he does programming as a hobby it means that he only used it a few hours a day for 6 months.

I don't quite understand why HackerNews gave so much importance to some random developer opinion on Rust.


Overall it's a great post detailing one of Rust's issues by the author, but this got me as well

> Rust's ecosystem, since Rust itself is reasonably young, is still in a developing stage.

> What I didn't know though, was that when you hit a road-block, finding a solution feels like navigating a jungle.

Living on the edge always has a price


When I saw "at least since March 2016," I wondered if it was a typo.


While I do agree that six month is not quite long, there's another issue: in the RFC PR, most of discussions took place before Mar 27, which is 10 days after when the RFC was submitted. Then there were a few comments on on Apr 28, and nothing really happened until Aug 4, when someone mentioned they were interested in the RFC, and there only has been minor discussions after that compared to the situation before Mar 27.

I might be wrong but judging from this, I felt like we might never reach a conclusion on this topic even in a considerably long enough time, since it did seem to me that the core team is not interested in this feature.

From this point of view, I don't think it matters too much when we debate if six month is long enough, even if we waited longer, I'm not sure if the situation is gonna change when interest in this feature stays low.


  > it did seem to me that the core team is not interested in this feature.
It was proposed by a core team member, even. Changing a language takes time. There's only so many people and so much work to do: the author of that RFC has also been working really hard on incremental recompilation, for example, which a lot of people have been waiting for.

To re-phrase someone from the Reddit, you can't win: if we don't add new features but fix bugs, people claim that you ignore feature work, but if you add tons of new features, people wonder why you're bothering to add new features when there's lots of bugs open. It's tough.


Rust seems to be a poor match for the way the author wishes to solve this particular problem. That doesn't mean that their design is wrong, or that Rust is wrong, but it does mean that mixing the two would require rethinking parts of the design.

> So a trait can define abstract functions, but can't access any underlying fields.

In Rust, a trait is a purely abstract interface to a type. It explains how you can use that type, but it knows nothing about the implementation.

I'm not quite sure what the design goal was with the Widget type, but the closest solution is to replace the member variable in the abstract type with some kind of accessor (and to replace the magic negative font sizes with an Option):

    trait Widget {
        // ADDED: Access whatever underlying font
        // size you have stored in this type.
        fn desired_font_size(&self) -> Option<i32>;
        // ADDED: Access the theme of this object.
        fn theme(&self) -> &Theme;
        // High-level interface to get font size.
        // (With a default implementation in terms of
        // other functions on this trait.)
        fn font_size(&self) -> i32 {
            if let Some(sz) = self.desired_font_size() {
                sz
            } else {
                self.theme().get_standard_font_size()
            }
        }
    }
I'm not sure this is how I'd personally design this, but it should compile.

> What IS the idiomatic Rust way to do a cyclical directed graph?

Unfortunately, the correct idiomatic way is that you try very hard to avoid doing so. Rust is all about clear ownership, and it doesn't like circular references.

The usual solution is to put the cyclic graph code into a library, and to use pointers and about 20 lines of unsafe code. (EDIT: See below for a better solution.) It's not much different from the C++ solution.

The Servo team really wants GCed, safe pointer support in Rust, and design work is well underway. But it's going to take a while to stabilize.

GUI libraries are an interesting special case: They involve huge class hierarchies, lots of implementation inheritance, circular references, and tricky ownership. Most older OO languages were optimized for this case. Newer languages tend to favor flatter type hierarchies and far less implementation inheritance. Which means that traditional object-oriented GUI designs may be awkward.


> The usual solution is to put the cyclic graph code into a library, and to use pointers and about 20 lines of unsafe code. It's not much different from the C++ solution.

Well, petgraph uses vectors and indices to avoid unsafe code, and it's the most popular graph library on crates.io.

Really, the answer here is "use a graph crate on crates.io". If you don't know which one to use, the best answer is probably petgraph.

> The Servo team really wants GCed, safe pointer support in Rust, and design work is well underway. But it's going to take a while to stabilize.

We aren't going to use GC'd pointers for any of the trees except the DOM. GC is way overkill for this use case. The reason why we want GC support is not to make tree data structures: it's for integration with JavaScript.


> Well, petgraph uses vectors and indices to avoid unsafe code, and it's the most popular graph library on crates.io.

Nice! I hadn't seen that yet, but it looks really interesting:

http://bluss.github.io/petgraph/doc/petgraph/graph/struct.Gr...


Not sure if it's just me, but the ampersands at that link are displaying super weirdly on my end:

https://i.imgur.com/Bg8rejM.png


It means you have an older version of source code pro, the Rust website uses your local font instead of an invalid font name like some websites do.


Happens here too (on Chrome 52-53.) I guess it isn't some locally corrupted font, eh?

Edit: Doesn't occur on IE 11, so it seems Chrome specific.


It's a locally corrupted copy of Source Code Pro. When I installed a new version it was resolved.


A lot of problems in Rust seem to involve replacing (smart) pointers with handles. Sometimes you really do want to do that, but it's bad if it's a necessary kludge.

Like someone else said recently, it's a problem if you can't reasonably teach a basic computer science course in Rust.


"Safe" Rust works for almost everything in a typical CS curriculum.

But if you want to teach an operating systems course or build cyclic, pointer-based data structures, you'll usually need a modest amount of "unsafe" Rust. Using "unsafe" gives you access to real pointers, which work just like they do in any systems language.

It's just that Rust chooses to lock those features away when you don't explicitly ask for them. If you actually need "unsafe", it's no more dangerous or more difficult than writing C code.


Where did you learn CS that they didn't have lots of cyclic data structures? We had those even in our intro class at Berkeley...


I a few universities I know, including my own, cyclic data structures are on the curriculum, but nowhere near being taught as basic or intro stuff. That would lists, queues, trees, and hash-maps.


The regular LinkedList in Java is implemented as a doubly linked list, which is cyclic.


When I took my degree we had one full year of data structures, Data Structures and Algorithms I & II, but they were taught on the third year (our degrees are 5 years).


It occurs to me that these courses have been teaching what might (should?) be considered a naive view of memory; you show me a traditional cyclic data structure and I'll show you a concurrency bug. I suppose that's fine in 1978 when no one imagined they'd be dealing with multi-core microcontrollers, but today, when you find yourself using a "systems" language for non-toy work and you reach for a tool as sharp as a raw pointer, those naive data structures are frequently (usually?) inadequate.


Cyclic data structures are in my experience very useful for concurrency. It's probably the number three good excuse for using a linked list, when you want to hold a lock for O(1) time with no shenanigans. But also, generally, anything that involves communicating information from point A to point B, and waiting on that information, involves some sort of cyclic reference between the sender and listener.


I have to completely disagree ... What are you even talking about? The inability to have circular links is deeply hobbling; they arise naturally in all kinds of circumstances.


> A lot of problems in Rust seem to involve replacing (smart) pointers with handles. Sometimes you really do want to do that, but it's bad if it's a necessary kludge.

It's not a kludge. It's how you prove to the compiler that you're using those structures safely.

If you aren't used to programming with compiler-enforced safety, you might be tempted to call working with the safety mechanisms a "kludge". But in reality all you're doing is doing things a little differently so that the compiler can ensure safety.


My basic CS course was taught in Standard ML. Pointers are an implementation detail for the vast majority of CS.


Using handles / indexes instead of pointers is a type hole and introduces similar problems of memory safety through the back door. The problems will be semantic in nature rather than more fundamental but will still be bugs.

For the article author, I'd recommend going down a virtual DOM like approach rather than traditional OO toolkit. Rust meshes a bit more closely with functional ideas than OO.


There are already some CS courses in Rust, Penn is running another one this upcoming semester.

(It's not a basic course, but you absolutely could.)


CIS 198 or something else? https://cis198-2016f.github.io/

I am currently "attending" the above mentioned course by following along online. I am enjoying it very much so far. There have been three assignments so far, the first of which was to get rust installed and such. I think it would take most of the HN crowd less than a week to catch up with the course so that they can follow it for the remainder of the semester, even if they have a day job. The most experienced programmers might be able to catch up within just a few hours.

The schedule at https://cis198-2016f.github.io/schedule/ has links to the slides, lecture notes and assignments.


That's the one!


> GUI libraries are an interesting special case: They involve huge class hierarchies, lots of implementation inheritance, circular references, and tricky ownership.

I doubt they have to be. There are other ways to do GUI, see for instance how Light Table uses a database-like Entity Component System. https://www.youtube.com/watch?v=V1Eu9vZaDYw


I am fairly confident "someone" could write a composition-based UI. I know of no fundamental reason why that would be impossible, or even any more difficult than doing one with inheritance.

However, that does not solve the problem that all the mature existing UI widget toolkits are based on inheritance, and that causes a serious "impedance mismatch" with languages that don't have inheritance.

As I expect more languages to start privileging composition over inheritance, I also therefore expect this problem to continue to become more acute until "someone" finally solves it. However, GUI toolkits are huge and "someone" is likely to be a substantially-sized organization. The problem is going to have to become very painful before it is solved well.


Granted, current GUI toolkits are huge. On the other hand, I have worked with Qt, and this convinced me most of the complexity there was a blend of avoidable bloat and a long tail of features few people ever use (a bit like offices suites).

I'm pretty sure properly written GUI toolkits can be much smaller. As in, satisfying 90% of our needs in a couple thousand lines of code. (The remaining 10% might require heaps and heaps of code, but I'm sure it doesn't have to affect the core.)

It's only an intuition at this point (I have yet to implement my own GUI toolkit). But I have reasons to believe this intuition is right: http://www.vpri.org/pdf/tr2012001_steps.pdf


Well, I guess I ought to put this in here, rather than rewrite it :) : https://news.ycombinator.com/item?id=12410471

The "long tail" is like the long tail of Excel or Word; yeah, everybody only uses 5% of it but everybody uses a different 5%.


    I'm pretty sure properly written GUI toolkits can be much smaller...
Given that as far as I know, there are no examples of tiny fully-featured GUI libraries (it's all either trivial like cgui or a massive bloated mammoth like qt/wpf/android), isn't that a bit of a rich statement?

Like, I'm sure you can write a procedural generator in a handful of lines of code that spits out the full works of Shakespeare. It's probably possible, if you have the right seed and the right algorithm.

...but practically speaking, how do you actually build one?

The same goes for UI libraries; certainly it should be possible (in theory) to have a minimal beautiful GUI libraries with an excellent API; but every attempt to build one seems to have failed.

Perhaps the problem domain is actually more difficult than you're giving it credit for...


vpri.org managed to squeeze a GUI toolkit and a document format and the whole compiler toolchain required for the language (including rasterization) in about 20K lines of code, and it's fast enough to run in a laptop.

I'm pretty sure we haven't explored the sheer depth of simplifications that can still be done.


Sounds cool. Got a link?

I can't find anything on their website that seems to be that sort of thing?


I doubt that you'll find much.. They didn't release the code of their "crown jevel" (Frank, the 'word processor'), which makes me quite unimpressed about these year of research where the main result is a bunch of papers and demos but (nearly no) code (except for the OMeta part).


I believe they did release the source code, not far from here: http://vpri.org/fonc_wiki/index.php?title=Installation_Guide (may be outdated, you may want to ask the FONC mailing list, may not work on your machine… it's a proof of concept anyway, not a hardened engineering artefact).

Their writing is here: http://vpri.org/html/writings.php

Their various reports are there (most recent first):

http://www.vpri.org/pdf/tr2012001_steps.pdf

http://www.vpri.org/pdf/tr2011004_steps11.pdf

http://www.vpri.org/pdf/tr2010004_steps10.pdf

http://www.vpri.org/pdf/tr2009016_steps09.pdf

http://www.vpri.org/pdf/tr2008004_steps08.pdf

http://www.vpri.org/pdf/tr2007008_steps.pdf


Maybe the word processor is there, maybe it isn't, there isn't much documentation, I've asked the FONC mailing list..


It's certainly a tricky endeavor, but not impossible:

- http://www.fltk.org/index.php - https://github.com/froggey/Mezzano

Then again most gui libraries end up including networking, file handling, etc...


You might be able to create something like React. The API would be composition-based, and the library would bottom out against an existing UI toolkit.


> > What IS the idiomatic Rust way to do a cyclical directed graph?

> Unfortunately, the correct idiomatic way is that you try very hard to avoid doing so. Rust is all about clear ownership, and it doesn't like circular references.

> The usual solution is to put the cyclic graph code into a library, and to use pointers and about 20 lines of unsafe code.

The point about C++ is important. Cyclic graphs are hard in any non-GC'ed language because it breaks the ownership story.


The usual solution is to put the cyclic graph code into a library, and to use pointers and about 20 lines of unsafe code.

That indicates a fundamental design flaw in the language.


In what conceivable way?

Safe Rust allows one to do an incredible amount of things whole providing strong guarantees against the sorts of problems that plague lower level languages. Since this isn't suitable for absolutely everything, we have unsafe Rust to fill in the gaps in the small areas it's needed. Unsafe Rust isn't "bad", it just doesn't provide the same guarantees as safe Rust. And if something goes wrong, you can at least narrow down your search to unsafe areas of the code.

This isn't the sign of fundamental language design flaws. It's the sign of a phenomenally well-designed language, where the downsides of seldom-needed yet powerful features are limited to only those areas where they're used.


I'm not convinced that cyclic data structures are a feature that's exotic enough to warrant breaking the language contracts. This thread alone shows that it's a common occurrence in tree structures. There will be likely be other structures as well.

So I'd think a better way than saying "don't do that - or if you have to, you're on your own" would be to analyze use cases and see which scenarios the language can satisfy. (As another poster suggested in making "parent pointers" an explicit language feature(


Agree. The language's memory safety system needs to support more common use cases. At least:

- Back pointers. (They're not owning pointers, and they have a well defined relationship with some other pointer. The language may need some way to explicitly say that.)

- Collections where not all slots are initialized. (This requires simple proofs by induction as you grow a collection into previously allocated unused space.)


You can always use std::rc::Weak if you need a cyclic data structure with weak references. That covers, I suspect, the majority of the use-cases for these type of structures.

For real, honest-to-god, cyclic data structures — just use unsafe Rust. Again, unsafe Rust isn't "bad". It's just unsafe. More care will be expected of the code to ensure that it exports a safe interface, but nothing in the language stops you from doing it. There's quite literally no loss of expressive power.


And if something goes wrong, you can at least narrow down your search to unsafe areas of the code.

No. That's only true if the unsafe code presents a completely safe interface to its callers. If the safe code opens a hole in Rust's protection system, which is very easy to do, you can now have C-type no-idea-where-it-is bugs.


But the origin of the bug is still certainly in the unsafe areas.


Yes, the crash can come from every line of code, but the origin of the bug is in the unsafe code. That's why unsafe code has to be cleanly inspected to be sure it has a safe interface, and by reducing the dangerous area to only few lines, it is far easier to do.


All languages have design flaws. Thats why people keep making new languages. Arguing that Rust does not have design flaws is going to arouse more skepticism then anything else.

It is not mandated that you 'must' write safe code but that you 'can' write safe code. So there really is no fundamental assurance that rust and its libraries are in fact 'safe' by Rusts own definition in any meaningful sense.

You could make the same style argument that C is a 'safe' memory language also as long as you use automatic memory management and no malloc. Of course that would be a rather disingenuous claim to make.


Nobody's arguing that Rust doesn't have design flaws.

That said, people also need to understand that many such instances are not design flaw, but are instead design tradeoffs. The OP indicated that having to switch to unsafe Rust to represent a cyclic datastructure is a design flaw. My response is that it's a tradeoff that pays dividends in every other piece of code.

Can Rust improve upon the number of problems that can be solved with safe vs. unsafe Rust? Absolutely! Is it worth cordoning off a few cases that don't technically need unsafe behavior, to ensure all other Rust code performs safely? Emphatically yes.


> All languages have design flaws. Thats why people keep making new languages. Arguing that Rust does not have design flaws is going to arouse more skepticism then anything else.

As somebody who has used Rust since late 2012, I completely agree. It seems that most of the more sweeping claims come from those new and excited users - hopefully over time this will soften and become more reasonable. Hype is definitely something that needs to be kept in check though, as it more than often results in a back-fire.


No it doesn't.

It indicates that idiomatic Rust doesn't like cyclic references and thus you must step outside safe, idiomatic Rust to do that, it really just means that every language has an idiomatic way to do things to stay on that idiomatic road and not every way of doing things fits the idioms - they're still possible but not idiomatic. Given how the ownership system works, it makes sense

You may say that that indicates a flaw in the ownership system, but it doesn't. The ownership system can do certain things, but not all of them - it's designed to prevent the majority of common memory safety violations, but if it can't prove everything. That doesn't indicate a design flaw, it indicates a system limitation, same way a GC pause it's not a design flaw, but rather a limitation of a well deigned system.


Which flaw does it indicate? It seems like there is nothing about the solution that contravenes the design goals of the language.


The fundamental flaw being the lack of a GC?


You write your cyclical graph implementation many times less than the implementation is used. The majority of the code need not deal with it.


Given that Rust was designed by a group known for writing web browsers, how does that work out in practice, given that the DOM is a deep bidirectional graph?

UIs work routinely by the organizational principle the author is attempting. Nested groupings of related functions that often interact in small groups.

And the thing is, a pointer to your parent doesn't semantically mean an ownership relationship anyway. It s in fact an extremely clear declaration of the ownership contract because while the owner can own many things, an object in this graph can have but one owner.

Now, I'm not sure how you would encode this into a compiler, so the discussion may have to end there as being impractical to implement.


> Given that Rust was designed by a group known for writing web browsers, how does that work out in practice, given that the DOM is a deep bidirectional graph?

I believe that the JS engine has ownership over the DOM, and pointers into the DOM are GC'd by the JS engine. This is part of the motivation for adding hooks for GC's in Rust. These posts [1][2] discusses this, although I think there is a more recent one. Edit: more recent one here [4].

> Now, I'm not sure how you would encode this into a compiler, so the discussion may have to end there as being impractical to implement.

This seems like a good use case for a Weak<> pointer [3].

[1]: http://blog.pnkfx.org/blog/2015/11/10/gc-and-rust-part-1-spe... [2]: http://blog.pnkfx.org/blog/2016/01/01/gc-and-rust-part-2-roo... [3]: https://doc.rust-lang.org/std/rc/struct.Weak.html [4]: http://manishearth.github.io/blog/2016/08/18/gc-support-in-r...


Meh. Using Weak Types for this would be circumventing the ownership system to say what you mean and maintain it by hand. Indeed I believe the Rust Language is essentially stating that you can't manage these things by hand but a computer can.

The road to hell is paved with good intentions, and I know myself and my cohort well enough that I appreciate the Rust sentiment on this subject. It was the main feature that drew my attention.

I'm wondering if this is a concrete concept that could be build into the ownership system. Logically speaking, this back pointer only exists to allow objects that are part of a Composition to reason about their environment, or be reasoned upon by an outside observer.

Maybe some of this information already exists in the language internals and you just need a function that can expose the owner of record of the object... There can only be one, right?


Each component could have it's environment passed in when called, rather than needing a back pointer. This also simplifies unit testing!


The JS engine manages the life cycle of all DOM objects. Other trees such as the flow tree just use reference counting and traits.


"The Servo team really wants GCed, safe pointer support in Rust, and design work is well underway. But it's going to take a while to stabilize."

Any details on this? GCs and finalizers don't really work well together, which is why I gave up on my cycle detector implementation.


http://manishearth.github.io/blog/2016/08/18/gc-support-in-r...

The reason Servo in particular would like GC hooks is because JavaScript is GCd and we want to be able to pass around Spidermonkey-managed pointers safely. We have a framework in place that does this, but proper compiler support would be nice.

Servo doesn't need to worry about finalizers because our DOM structs never have nontrivial destructors (explicit Drop impls).

The blog post throws around some ideas for dealing with the finalized problem though.


They want objects that can be shared with Javascript.


The solution is to implement guis with composition and delegation rather than inheritance. It requires some ree-thinking and elbow grease, rather than just copying stale designs from 30 years ago, which may be why so many people avoid it, though.


> GUI libraries are an interesting special case

> traditional object-oriented GUI designs may be awkward

For example, Qt has moved that tricky part into a specialized language. I think that it's the way to go.

So it's okay if a low-level language is not designed to do that ancient stuff with pointers to widgets.


Also note that there are actually several QML for Rust implementations out there, and while I've only done weekend toying at least qml-rust works well.


It seems the author is trying to do classical OOP using traits (type classes). They aren't a match although the similarities.

I understand his rant, but I don't think it is a valid one. You must change your design or change your tool, he opted to change the tool.


I hit the same wall, and opted to learn a new way of design after years of slavishly adhering to OOP.

There's not much that I miss from OOP, and I now see its utility as more about making the ability to program scale predictably with an unpredictable workforce.


So, you want class based polymorphism, and you want trees of objects with back references. Sounds like Qt to me. I have the feeling the author tried to translate his knowledge of OOP languages to Rust.

Bad idea. Try F# first.

Seriously: my current favourite language is Ocaml, and it would have basically the same problems. But I don't care, because I don't think like that. I have other ways to solve my problems.


Ocaml has a GC and supports class based inheritance, right?


> Ocaml has a GC

Yes, but the language is immutable and eager by default. That makes circular references a chore.

> and supports class based inheritance

Yes, but hardly anybody uses that part of the language. We tend to stick with modules and variations over them.


> Yes, but hardly anybody uses that part of the language. We tend to stick with modules and variations over them.

You can have inheritance via polymorphic variants: see Garrigue's `Code reuse through polymorphic variants`.


I have never used polymorphic variants… Too lazy to learn.


Actually, I think most of the OCaml GUI libraries (lambda-term, for instance) do use objects and classes, because it makes sense in that context.


You can drop something when you use it some noticeable amount of time, not just couple of weeks. Otherwise it's more "I tried but it's not for me". There's nothing wrong with it - somebody will love Rust, somebody will not, somebody will love even Go - it's ok.

But title is too dramatizing.


> somebody will love even Go


The author seems to be confusing typeclass composition with OOP. They are only topically similar. (Personal opinion; typeclass composition is more principled than OOP, but a bit more rigid, which he is running into.)

There are several good ways to do this with type classes/traits. One way is to write a function

font_size : Widget t => t -> FontSize

And then in the widget definition have the "internal" font size defined, which the author seems to be assuming the existence of for some reason.

Additionally, in a language like Rust with ADTs, there's no good reason to return negative numbers to signify things like a missing font. He should be returning Maybe FontSize if he wishes to signify that an object may not contain a font size.


> The author seems to be confusing typeclass composition with OOP.

I agree and would like to expound on that idea. One of my biggest frustrations with inheritance in traditional statically typed languages (I program in C++ for a living) is that inheritance is performing two functions at once: code reuse and typing. Confusing the two seems to cause a lot of pain. Inheritance as a type system is describing the kinds of things the object can do. Inheritance is (usually) a sufficient condition to say that the types can be used interchangeably. Making inheritance the only way to express the type information often forces some very unfortunate code.

The author is trying to use traits as a code re-use mechanism. He wants the trait to be able to see into the implementation and be a function of the implementation's private data. If that were allowed, that would invite all of the pain of inheritance for that kind of trait. Types with a different internal implementation would end up being awkward at best.


This sounds like a failure of the Rust documentation.


The documentation is supposed to tell you what the language is, not exhaustively detail everything the language is not.


No, it's supposed to teach people how to use the language. When a large fraction of your user base will be bringing a specific skill set, then you should generate documentation aimed at translating those skills!


You've described tutorial, not a language documentation set.


Exactly, you can't expect to "port" code across from languages in different paradigms without rethinking the design a little bit.

I really like traits/type classes over OOP-style type systems but sometimes it causes a bit of impedance mismatch.


I've picked it up and put it down a few times now. It is super humbling to feel like I've been reset to total newb status after decades of work with software, including OO, imperative (with and without GC), declarative and functional languages.

I'm still interested and motivated to learn more. I hope to get a chance to spend time on it at work because a free hour here and there isn't enough for me to absorb this stuff.

And confession time: I haven't even done too much fighting w/the borrow checker, I'm still slowly absorbing the type system and other general stuff.


My thoughts exactly.

My confession: I've fought the borrow checker and lost a few times, and just scaled back what I wanted to do, so far.

Maybe someday I'll know what I'm doing :-) but I do like it so far, certainly more than C++.


Just keep plugging away and finish something. It took me three projects to get to the point where the cognitive load of what I no longer had to worry about exceeded what I had to worry about.

It's hard to describe, and to say "if it compiles, it works" is not 100% accurate, but I would say "if it compiles, it works, and if it doesn't work, then I know it's my own logic error". It's like Rust guides you into the space of correct solutions and cleaner code when compared to other languages.

The other thing: there are huge dividends you reap from spending time in Rust that are realized when you go back to other languages. If you've spent your life in managed runtimes or more loosely-typed languages, you come away better for the time spent in Rust.


> the cognitive load of what I no longer had to worry about exceeded what I had to worry about.

Yup, this has been my experience too. I started using Rust for my primary project last March and was worried a little at first about the risk of wasting too much time, but at this point I'm ~1.5x to 2x as productive as in C++11:

* essentially no more "head-scratching action-at-a-distance bugs" (I've spent N years in C++ and I still sometimes invalidate an iterator) -- as you say, any errors that still exist are higher-level logic errors, which are (in my experience) much more straightforward to track down.

* enums and match/destructuring and all the builtin types (e.g. Option, Result) have me thinking in a much more strongly-typed and principled way. So even logic errors tend to be less frequent because I break down the problem the 'right' way immediately. Algebraic datatypes let one describe a state space really succinctly.

Rust is one of those languages that really, strongly wants you to be idiomatic, but it pays off!


On trees: Can you use regular references for the children, and weak references for the link back to the parent? That's a valid structure that tears down properly. With strong backpointers, when one of the objects is deleted, there's a moment when there's still a live reference to it. That's invalid under Rust's rules, so you can't do that.

There's also the option to own all tree objects with some collection for allocation purposes, and use weak references for all inter-object links.

As for traits, Rust does seem to have an overly novel and complex type system, and I'm not going to defend it.


The only real difference between a weak and strong pointer is that weak pointers are less prone to leaking memory (in exchange for the possibility of "sorry I'm dead" being a response to accesses). As soon as you upgrade such a pointer you've created a cyclic graph.

He only way for Rust's type system to understand these kinds of access patterns in a way that doesn't require the insertion of "shared mutability" types (e.g. Mutexes) involves mutating the tree during traversals.

A simple version of such a pattern: a "doubly linked" list which is actually two singly linked lists. One "traverses" this list by popping nodes off one and pushing them onto the other. The user has easy access to the heads of both lists. You could probably do the same with trees but this is a pretty unpleasant pattern.


Tree zippers can be pretty nice to work with, no?


You don't need weak references. Just use strong ones.


Then you have an ownership loop.


I meant reference counted strong pointers. Non-reference counted weak pointers make no sense from a systems point of view: in order to be memory safe you have to track the number of outstanding pointers, which is effectively a reference count, so you might as well be honest and use a real reference count.


I don't understand why the author wants to access fields from a trait. They can be accessed by the trait implementations, which makes sense, because the fields depend on the type.


You should check out the RFC they linked; there are good reasons to enable this.


Thanks! Here are the reason why trait fields are preferable over accessors in case anyone else is wondering:

1. The borrow checker assumes accessors can do anything, freezing all other fields. This does not happen with trait fields. 2. Accessors have to use dynamic dispatch in case of trait objects, resulting in worse performance.


It seems like maybe rather that just porting nanogui it might have made sense to do a bit more translation/conversion of the patterns used in it to what rust encourages/makes easy...


> For other use cases, Rust is still lacking. One such use case would be an OpenGL GUI, like CEGUI or nanogui.

I'm curious if anyone has tried developing a Qt5 app in Rust -- are there any Rust-ic bindings out there?



Wasn't really able to follow the bit about traits but:

It seems like if you want to have back-references you either would need to use Rc<RefCell<T>> or Arcs, which is not the end of the world.

The best way to do it would be to not have back references at all. Then you could simply have Vec<Box<Widget>> for children.

If I were going to build a GUI system in rust I certainly wouldn't design it to be OO. I think you would repeatedly run into problems. An entity component system or something like react might work better in rust.


> However, a trait has no knowledge of the underlying implementation. So a trait can define abstract functions, but can't access any underlying fields. > ... > Let that sink into you. My first reaction to this was "Sorry, what?!". While there are valid criticisms against OOP, to offer this as a solution is just silly.

This is a misunderstanding of what traits do. Interfaces in Java have no knowledge of the underlying implementation, either. And more generally, neither does an ABC: you can't use fields you don't declare in the ABC in methods declared in the ABC.

It is sad that Rust traits can declare only functions, not fields; so you must redeclare your fields as methods if you want to be able to use them as part of a default implementation (I think). Later the author explores this option -- but notes the "field methods" must be public along with the real interface of the trait. I am not sure what options Rust provides for making them private. For example, it might be possible to split the trait into a public and a private half. (But maybe not: https://github.com/rust-lang/rfcs/blob/master/text/0136-no-p...)

I do question the wisdom of the author's design at a higher level, because the author is using a trait for provide an implementation, not just an interface. If the implementation really applies to everything that matches the trait, it should probably be provided with a generic. If not, it is at worst tedious, but hardly limiting, to recycle a generic definition by calling it in an implementation.


> what IS the idiomatic Rust way to do a cyclical directed graph?

That's a great question! So, uh, what is the answer?


Some kind of adjacency list combined with a standard container?


I have been feeling that way ever since two years ago when I first looked at the language. I still don't understand why this language has such popularity. It's really bad for the reasons mentioned. C++ is a solid language where you can do everything you want and also write memory safe code in a clean way with unique_ptr. C++ is not perfect but to me no alternative come close yet, rust and go comprised.


You can write clean safe code in C++, Rust tries to turn that can to a must.


C++ is not memory safe, and neither is uniq_ptr. Use after move on one causes a segfault. (Actually IIRC it's UB, but it usually manifests as a segfault)


It looks like clang-tidy just committed a check for this case: https://reviews.llvm.org/D23353


Not exactly this case. From the link:

  > No warnings are emitted for objects of type ``std::unique_ptr`` and
  > ``std::shared_ptr``, as they have defined move behavior.
Regardless, I am happy to see more static checking for C++, and am following the GSL/Core Guidelines closely. It's important work.


C++ is not memory safe. unique ptr provides no protection against dangling references. Besides, you cannot use unique ptr to make backreferences, which is what this article is complaining about.


The very first complaint seems to totally miss how traits are interfaces, not classes. Doesn't make enough of an impression to keep going...


"There's simply no way to tell the compiler to not drop a variable automatically when it goes out of scope."

Perhaps std::mem::forget


I've been observing in some stronger critics about Rust a persistent focus on OO features, usually the ones that programmers tend to rely upon and which they feel to be "lacking" in Rust - usually requiring a different structure or abstraction which the programmer is not familiar with.

The issue about parent/children pointers mentioned in this article seems more a lack of understanding on the concepts of ownership and the traits system, for instance. It's indeed a harder problem to deal with in Rust if trying to apply a OO mentality, but one can find a way out if trying to understand the language first.

I have my personal thoughts about parts is Rust that could be improved; nevertheless, I don't see any issue with us excursions, and consider it an evolutionary step which brings system programming languages to a new level.


What "non-OO" methods for representing cyclical data structures are you referring to? The only one I can think of is lots of indirection (e.g. how petgraph does it), which can be too slow (especially for systems programming). As far as I can tell, Rust's model for verified code is pretty hostile to cyclical structures, especially if you want inhomogeneous references (i.e. not everything is an edge on a graph). I don't think you can just sweep this under the rug as "lack of understanding" of Rust's better ways of doing things.


Someone should write a good book on Rust's approach to OOP and how it differs let's say from classic C++ when doing actual library design. Despite all the good documentation on Rust, this topic is really lacking clarity.


Why I'm dropping Rust (hackernoon.com)

Why the redirect from medium.com?


>In languages such as C++ or C#, this is an easily solved problem. You create an abstract class or a base class depending on language and inherit that in your actual class.

Oh cool an anti-pattern being described as an "easy solution".


I wonder how many of his problems could have been solved using the 'unsafe' keyword. I'm naively familiar with Rust through the various news postings, but know it has the unsafe escape hatch.



I think it would be fair if you also would disclose that you are working in Mozilla and that you are directly connected to Rust when defending it on HN.


Nah, most HN readers know that and the rest are smart enough to figure it out.

We appreciate your concern for the integrity of the community. On the other hand, posts like this lead to flurries of offtopicness, so their cost/benefit is usually poor. We detached this subthread from https://news.ycombinator.com/item?id=12474588 and marked it off-topic.


I think pcwalton's extensive knowledge on not just how to program in Rust, but the rationale behind various design decisions should indicate to a careful reader that he is involved in Rust.


I disagree. I can know various decision behind various designs from reading what's going on github. And i know some of those decisions in different languages other than Rust, which doesn't indicate that I am involved with them.


While disclaimers are common (for some reason), it has no effect on the virtue of his points.

It's just fluff.


I have different opinion on that matter. Sure, some of his points are valid, I even agree with some of them but not all and not always. That's why disclaimers exist, for that reason. Especially when there are cases of glorifying your own product and bashing others.

Please read this:

https://en.wikipedia.org/wiki/Bias


Do you honestly feel like this comment would help a person to see your side of this?

It's a basic assumption that anyone who speaks positively about a thing is biased in favor of that thing. We don't need to point out every instance of that bias because it would dominate every discussion while providing no value because it is something everyone fundamentally assumes in the first place.


As i noted before i agree with some of his points which means that i don't think that all his opinions are only driven by his bias. But that doesn't change what i wrote before especially if one can distinguish between what's valid technical fact and what's not.


The purpose of disclaimers is to preemptively shut up bozos that would accuse you of commenting in bad faith, not because it's right to do.

And it isn't bias if you're right.


Have you made positive experiences with linking fairly long Wikipedia article to people who disagree with you?


Sounds like overkill to me? Would a comment in a profile be sufficient?

(Disclaimer: I'm working on a web based brainfuck ide/compiler/optimizer for my own amusement, and thus probably have some kind of dog in some kind of fight here?)


I think an affliation heads-up is required if you are pissing on a competitor's product. And in such cases, HN does effective policing.

It is also possibly helpful if the commenter is elaborating on product that they are involved in to establish that their input is authoritative.

And not to give cause for inflated heads here :) but seriously, if you are seriously interested in this space, you sh/would already know the cast of mvps and thus major contributors such as Russ Cox or Patrick Walton (et al) would not require introductions.


Sure, comment in profile would be sufficient.


Honestly, just about anyone who's read an HN thread or two on Rust should be familiar with pcwalton's involvement with Rust at this point. I also don't see why he should have to insert a disclaimer paragraph in every single HN comment he makes.


He can make it inside his profile. Then i am not anyone because i didn't know he was involved in Rust some time ago, i learned that by a coincidence some time later.


Why? It would be fair if he was trying to push a product, but here it's just a technical discussion.


I am not claiming that he is pushing the product, just that his opinion can be biased, but then how would you want to push clearly technical product like Rust without technical discussion?


If actually knowing what you're talking about is a harmful form of 'bias', pretty much any informed post on HN would need a disclaimer at the bottom.

Then again, that'd make it easier to filter out all the uninformed/overly cynical/inflammatory posts!


I think a point you haven't considered when talking about bias is bias going the other direction. That is, if he were to mark his, technically oriented mind you, posts with information that he works on Rust it's possible that it will instill a bias among readers. Regardless of his association with Rust as a project he knows technical details and that's what's important in posts like this regardless of potential bias.


It's probably worth noting that a lack of affiliation would not imply a lack of bias.


Why do you think it would be fair? Are you implying he is biased? But aren't we all biased for our own pet technologies we advocated, use and convinced others to use?

To put it another way, is his argument or point invalid somehow? But then it would be invalid regardless if he worked for Mozilla or Microsoft or Google


Because humans are only humans, we are biased more if we are emotionally involved in something, more time you spent creating something, investing your time, more you are biased. It's about level of bias also, someone that is only using some technology is not so biased as someone that is creating one. It's psychology 101.


people shouldnt have to preface their statements with disclaimers whenever they comment on a topic, especially in such an informal setting.


It sounds like you'd like a signal that allows one to more quickly switch off their brain, like network television prefixing party affiliation to politician's names. "Oh it is a R talking? Well as a D I can assume that everything said is wrong, no need to evaluate individual points."


No, for me it's making the brain to see the whole picture, not turning it off. If you choose to turn off your brain when you have more information about person that is giving his personal opinions then it's your own choice. I even wrote in other comment that i agree with some of his points which contradicts your "no need to evaluate individual points".


What possible use for the additional information is there except for an appeal to authority (which isn't useful in technical discussions)?


Why would I care?




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | DMCA | Apply to YC | Contact

Search: