Settings

Theme

Rust and the Blub Paradox

jonathanturner.org

87 points by filsmick 10 years ago · 89 comments

Reader

bluejekyll 10 years ago

> What does the C++ code print?

And there it is. I programmed in C++ long enough to "know" this, but I still remember more jr. Engineers and even arguments with more sr. Engineers around this type of question.

Rust has removed this kind of question almost entirely from the language.

Personally, I have no intention of ever going back to C/C++ for any new project I work on.

  • mpweiher 10 years ago

    Of course, this has nothing to do with OO, and everything with C++.

      "I invented the term Object-Oriented, and I can tell you I did not have C++ in mind" -- Alan Kay
  • alimw 10 years ago

    > What does the C++ code print? If you guessed wrong, don't worry. You're in good company. If you guessed right, congrats!

    How do I knowwww????

lobster_johnson 10 years ago

I think articles like these beg the question. It introduces a claim ("many/most people think some languages are too weird") and tries to refute it without first showing that the claim is true.

Sure, I see lots of evidence of junior developers living in a happy bubble where they apply language X to everything, when they could expand their horizons a bit by looking into Y and Z.

But this also ignores important factors such as:

* Convenience — if you've highly proficient in X, there's a low barrier to entry for anything you want to accomplish.

* Private ecosystem — if all your code is in X, you have potentially tons of reusable modules as part of your own stack.

* Public ecosystem — lots of libraries and community support.

* Mature documentation

* Stability

* Ease of hiring

and so on.

Also, not least: The journey of every developer is to broaden one's horizons gradually. As a junior you'll likely slog through a few fad languages until you reach a point where every technology out there, no matter how advanced, will suddenly become approachable.

The Blub idea also ignores the fact people can accomplish great things with poor tools. Choosing a minimal tool does not necessarily say anything about you as a developer. Sticking to one tool for many years probably says a lot about your ability to develop your skills, of course.

In short, I think Blub is a red herring, and I think it's a condescending one, a product of survivorship bias — you're not superior because you succeeded using a certain set of tools. You're probably successful for other reasons (which may correlate with your ability to choose the right tools, or not).

Graham's observation that "[languages] dictate the way [developers] think about programs" is the more important lesson to draw from his essay, though it's not exactly a new idea.

  • pka 10 years ago

    I want to respond to one point specifically: `Private ecosystem — if all your code is in X, you have potentially tons of reusable modules as part of your own stack.`

    Never ever in my OOP days have I been able to reuse a non-trivial function from a different codebase "just like that". This is because all my functions were impure - something encouraged by most mainstream languages. So I had to first rip out the context the function was living in and make it work again before being able to use it somewhere else. I wouldn't fix it in the original place though, so next time I'd want to reuse I'd have to repeat every step again.

    Since I started using a pure language, reusing code actually became possible. I can rip out a function and place it in a new codebase without changing it a bit and it's gonna work just like that, no problem.

    Getting back to the topic at hand, I would define the Blub paradox as "being unable to logically explain the benefits of something solving a problem you haven't realized is actually a problem yet". This may sound like trying to create problems out of nothing just so that they can be solved by "cool feature X", but I'd guess in most situations this isn't the case.

    I truly believed that I was creating reusable OOP components until I realized that actually I wasn't. I truly believed a normal editor is more than sufficient for my needs until I learned vim. I truly believed svn was the best thing ever until I learned git. Etc...

    • lobster_johnson 10 years ago

      I didn't mean copy-paste reusability, I meant packaging code into reusable modules (e.g., NPM packages, Ruby gems).

      This has nothing to do with OO, really. But I don't disagree with your point about immutability.

  • microtonal 10 years ago

    The Blub idea also ignores the fact people can accomplish great things with poor tools. Choosing a minimal tool does not necessarily say anything about you as a developer.

    In fact, I think the original essay makes quite some unwarranted assumptions:

    But if you work for a startup that doesn't have pointy-haired bosses yet, you can, like we did, turn the Blub paradox to your advantage: you can use technology that your competitors, glued immovably to the median language, will never be able to match.

    The median language will probably have a very good ecosystem that allows a small team of developers to quickly leverage. (Of course, someone who is not stuck in a Blub language has the same opportunity.) I think that there are very many counter-examples to the 'blub paradox'. Facebook was written in PHP, Paypal was written in Java, Dropbox was written in Python (which was a Blub language by 2007).

    Graham's observation that "[languages] dictate the way [developers] think about programs" is the more important lesson to draw from his essay, though it's not exactly a new idea.

    Indeed, this is a very important lesson, but not foreign to anyone who learnt LISP in the 70ies or Prolog in the 80ies ;).

    • lobster_johnson 10 years ago

      Absolutely.

      Someone once claimed — I forget who and where — that Go was designed at Google precisely so that even average developers could contribute meaningfully and safely within Google's stack.

      Of Google's top languages (as far as I know), Java and C++ are complex, and Python has its own idiosynchracies, notable the lack of static typing which leads to a class of potential errors (especially as relates to backwards compatibility between modules) that must be mitigated with super-extensive unit test coverage.

      Go, on the other hand, is a very small and simple (easy to ramp up), very strict (hard to screw up) language with an extensive library (max productivity).

  • pekk 10 years ago

    The implication that a developer is junior if they mainly use one language is completely absurd.

    • lobster_johnson 10 years ago

      I don't see how you could interpret my comment that way.

      A junior dev might use a single language because they apply what they know and don't go outside their comfort zone. A senior dev might use a single language for every other reason.

    • joncampbelldev 10 years ago

      Everyone has a language they like best and spend a lot of time in (due to current job or side projects or whatever), but a developer who has never branched out to other languages and paradigms even to experiment for a bit (maybe bring back some knowledge to their preferred language) is someone I wouldn't want to work with.

      But this is all from my perspective in a small startup where people have very broad responsibilities. I can completely understand a very senior developer working in a specific field (usually it's the low level stuff with C etc) who only works in one language because there's just no opportunity to use anything else.

      Or perhaps someone who just sees their job as a 9-5 thing and looks elsewhere in their life for learning and growth.

hsivonen 10 years ago

In his CppCon 2015 keynote, Herb Sutter talked about retrofitting Rust's core concepts (not phrased like that!) onto C++ as a static analysis pass distinct from the actual compile. Unlike Stroustrup, he acknowledged the existence of Rust but said the lifetime annotations are too verbose.

Rust has lifetime elision for the common cases, though. It's unclear to me if the criticism was based on a pre-elision version of Rust.

In some talk, Andrei Alexandrescu said D is pursuing GC removal.

It'll be interesting to see if D and C++ with lifetime annotations can achieve useful results with less syntax for the cases where Rust's elision doen't work and you need explicit lifetime annotations in Rust. I have doubts, but of course both Alexandrescu and Sutter are working on Rust's competitors, so one would expect them not to say that Rust's more awesome than their languages.

  • pcwalton 10 years ago

    > Unlike Stroustrup, he acknowledged the existence of Rust but said the lifetime annotations are too verbose.

    As far as I can tell, this was an incorrect claim. The ISO Core C++ lifetime elision rules aren't meaningfully more aggressive than Rust's. We could easily add more elision to Rust if it turned out to be necessary, but the cases in which ISO Core C++ has extra lifetime elision rules that Rust doesn't don't come up often enough to make a difference.

    Lifetime elision is a double-edged sword anyway. It's somewhat controversial in the Rust community, because it's not reading the lifetime annotations that causes the cognitive overhead: it's the semantics and what the compiler will enforce. Having fewer lifetime annotations can actually make the code a lot more confusing. Based on experience, I would caution C++ to not go overboard with it: being able to show pretty code on slides is not worth confused and frustrated users.

    • Manishearth 10 years ago

      > It's somewhat controversial in the Rust community

      We added a lint to clippy that detects places where you could rely on elision but don't. I'm particularly fond of it, because many Rust programmers (including me) still default to the pre-input-output rule regime by explicitly typing out `fn<'a>(&'a u8)-> &'a u8`. It's caught a lot of this and made code nice and clean.

      However, we've have multiple people ask the lint to be off-by-default for input-output cases where one of the two sides has a struct/enum lifetime (`Foo<'a>`, not `&'a _`), because it's nice for that to be explicit. (At the same time, multiple people feel like it should stay)

      We'll have to see what happens when we RfC the clippy defaults.

  • steveklabnik 10 years ago

    The CPP Core Guidelines are simlilar, but different. For example, Herb also said that data race prevention is a non-goal, and they still don't have any idea of how to handle concurrency.

    That doesn't make them bad, just different! I welcome any effort to make C++ more safe, there's a lot of code out there that could benefit.

saurik 10 years ago

I think "blub" is relative. I look at people who think that cluttering code with boilerplate for error handling, and even those who think that boilerplate is sufficient is sufficiently papered over using macros, have yet to understand why exceptions are interesting or (often) how to use them correctly (as many uses of exceptions that people like to poke at are entrenched wrongness, much like how many people who hate the entire idea of relational databases really just hate MySQL, its limitations, and the attitude of its ecosystem). I feel one of the reasons I have been as productive as I have been over the years is that I have spent a lot of time studying error handling and even now have a sort of "theory of errors" that I will sometimes draw out for people on a blackboard. From my perspective, Rust is currently "unusable", though very compelling and will hopefully fix this problem. As much as I agree with other things it has built, and as much as I agree that my attempts to simulate those things in other languages have disappointing holes, after having spent a lot of time studying languages like Erlang and Haskell (and even as someone who teaches a class at a college on programming languages at the college level), not having exceptions or anything better than try! is a deal breaker for me, and while this person jokes about monads and how learning them might not be important, they would be well served learning why monads are interesting. One could even argue the entire section about error handling and how this developer is happy about how "straightforward" Rust is in comparison to monads is the "blub" issue rearing its head, but between Rust and Haskell. (The use of the word "straightforward" is always particularly concerning to me, as it is the general argument one uses for programming in C or Java instead of anything that hides intent.)

  • pcwalton 10 years ago

    Rust's error handling is, empirically, not unusable. I use it every day.

    Even Go's error handling clearly isn't unusable, as controversial as it is, and try! is pretty much just a more sugary version of it.

    Also, we were well aware of monads when we designed the Rust error handling system and in particular why they do not work very well in languages that have rich, imperative control flow structures. try! is basically just monads for imperative languages. To see this, work through what happens if you try to add break/continue/return to Haskell's system.

    • steveklabnik 10 years ago

      I still don't fully understand the break/continue/return argument, at all. I should bug someone to actually write this up.

      • pcwalton 10 years ago

        An oversimplified version: the monad rules/type signature only allow for possibly-recursive sequences of statements. That admits straight-line code as well as if, while, and for. But it doesn't allow for any exceptional loop exits (more formally, doesn't allow for any backwards edge from node A to B unless A postdominates B).

        There are ways to transform code to allow this to work (there has to be, since Haskell is Turing-complete), but it's not straightforward.

        • steveklabnik 10 years ago

          I guess I'm just not sure why this is a problem, exactly. Even if you couldn't use those statements inside of a `do` block, that shouldn't be an issue? Just like using `break` outside of a loop is invalid, it would be the same here.

          The Option monad already is a sort of early return. Inside of monadic combinators, you use the monad for control flow instead of those statements. Seems fine to me, though admittedly my Type Theory Wizardry isn't the strongest.

          • pcwalton 10 years ago

            do is only really good if you use it for the whole function, or at least have some way to get the error out of the do block to the code that's supposed to handle it. But if break isn't allowed inside a do block, then if you need to break you have to split up your do blocks into blocks before the break and after the break. Now if there's an error thrown by one of the statements in one of those do blocks, then you have no straightforward way to propagate it out of the function. You would need to pattern match on the result of each do block and return the error if there was one--in other words, you would need to write try!

            This is why I called try! monads for imperative languages: the early return that is expands to is the key to playing nice with imperative constructs like break and continue.

            • steveklabnik 10 years ago

              The usual implementation of the Either/Option monads already does this though:

                  instance Monad Maybe where  
                      return x = Just x  
                      Nothing >>= f = Nothing  
                      Just x >>= f  = f x  
                      fail _ = Nothing  
              
              and

                instance (Error e) => Monad (Either e) where  
                    return x = Right x   
                    Right x >>= f = f x  
                    Left err >>= f = Left err  
                    fail msg = Left (strMsg msg) 
              
              The end result is still a value of that type. You get the short-circuting behavior as soon as you hit Nothing/Left.
              • pcwalton 10 years ago

                It only short-circuits to the end of the do block. But once you leave the do block the error isn't propagated anymore.

                • steveklabnik 10 years ago

                  Right. Maybe this is because I tend to write small functions, but the amount of things that end in `Ok(())` especially with IO still makes me think it would be useful.

            • pka 10 years ago

              Can't break be simulated by something like MaybeT? And forWithBreakM :: [a] -> (a -> m (Maybe b)) -> m [b] that stops when f yields Nothing? (isn't this actually sequence . forM?)

              • pcwalton 10 years ago

                Yeah, there are transformations that we could apply to the code to make it work. But those transformations aren't trivial in the general case: how about breaking out of multiple loops or returns out of the function from inside loops? At some point, the transformations that we'd have to do would get so complex they'd hinder the programmer's mental model of what code will get generated. We'd also have to do a fair bit of work to make sure the optimizer can figure out what we're encoding so as to not lose performance.

      • dbaupp 10 years ago

        I wrote a comment a while ago that has some code examples: https://github.com/rust-lang/rfcs/pull/243#issuecomment-8220... (and the following two comments)

  • tome 10 years ago

    > I have spent a lot of time studying error handling and even now have a sort of "theory of errors" that I will sometimes draw out for people on a blackboard

    I would be very interested in a blog post on this.

  • steveklabnik 10 years ago

    Have you seen https://github.com/rust-lang/rfcs/pull/243 ? What do you think of it?

  • Rusky 10 years ago

    What do you see as unusable about Rust's error handling? It's heavily inspired by monadic exceptions.

  • Manishearth 10 years ago

    Rust errors _are_ monads. That style of error handling is known as "monadic error handling".

    When the blog post says "you don't need to learn monads", it's being tongue-in-cheek. He's pointing out that whilst Rust errors are monadic, you don't need to learn monads to work with them.

    To be fair to Haskell, it doesn't force you to learn what a monad is either (ha!), but often the full details of what a monad is are emphasized before teaching IO or error handling. Which works somewhat, but also gives monads their infamy.

  • eximius 10 years ago

    I think many of us would be interested in such a "Theory of Errors"

chao- 10 years ago

I haven't written C++ with any significance in a few years, and done little with Rust at all. So while I don't feel qualified to speak to the comparison at the core of the blog post, I did find the first example to be disingenuous. It rests entirely on assuming the C++ programmer will rely on inheritance to achieve polymorphism, simply because they can?

Additionally, the C++ example doesn't produce the same output ("Value: (x: 7)" and "Value: (x: 5, y: 10)"). The addition of that goal might lead the programmer to treat the C++ version of print_me as something more abstract, accepting a string and having class Foo and class Bar simply return their own string representations.

I acknowledge that the premise was "a beginner C++ developer", getting hyped up about inheritance and using it as the only tool in their toolbelt, but how many people are learning C++ as a first language these days? It used to be the norm, back in the OO-will-save-us-all heydey, but has anyone run into it lately?

  • bluejekyll 10 years ago

    Don't forget about how awesome C++'s multiple inheritance is! <sarcasm/>

    edit: It's worth the down votes on this. Multiple inheritance is pure evil and confusion. In fact, even in Java I now rely on aggregation over inheritance.

    http://stackoverflow.com/questions/269496/inheritance-vs-agg...

    • mercurial 10 years ago

      Unfortunately, in some languages, inheritance of abstract classes is the only way to get the equivalent of interfaces.

      That said, yeah, the less class inheritance, the better. Ideally, work in a language where interfaces can include default implementations.

      • bluejekyll 10 years ago

        Totally, no problem with default implementations as long as they are generic. Java finally supports this, as well as Rust and others.

    • GFK_of_xmaspast 10 years ago

      c++ is a great language but a lot of the inheritance system is regrettable at best.

draw_down 10 years ago

This article is a bit all over the place, and the basic premise is not very good.

The Andrei guy says that Rust places too much emphasis on "clerical" memory management. This is not like a person who learned PHP from a couple w3schools article deciding that Lisp is "weird". The criticism is not that Rust is "weird" or somehow unintelligible, it's a direct critique of the language designers' choices.

This is the danger of using rules like the Blub paradox, you have to be careful or everyone who doesn't agree with you or doesn't like what you like is a Blub-programming dullard.

I actually do think there is something to the paradox, I would even say I have occupied different parts of that "ladder" myself. (That is, I'd like to think I'm higher on it now than I used to be.) But maybe JS programmers aren't interested in type-checking in their JS precisely because they prefer JS for its dynamically-typed nature. This is as opposed to someone coming to JS from a different language and bringing their preference for strong typing with them.

Then the author goes on to talk about a bunch of stuff that does nothing to explain Rust's apparent emphasis on memory. It's pretty much just a list of why Rust is cooler and better than C++. That's fine but none of it addresses the point made at the outset.

  • dbaupp 10 years ago

    > The Andrei guy says that Rust places too much emphasis on "clerical" memory management. This is not like a person who learned PHP from a couple w3schools article deciding that Lisp is "weird". The criticism is not that Rust is "weird" or somehow unintelligible, it's a direct critique of the language designers' choices.

    It might be a direct critique, but it's a critique of an incomplete picture of Rust: the rules that allow Rust to avoid a GC offer benefits far beyond just that, such as being a core component of Rust's concurrency story[1], and avoiding problems such as iterator invalidation (not generally a memory safety problem in a GC'd language, but still a semantic one, e.g. Java's ConcurrentModificationException).

    (The "Weird feature #3" part of the article is exactly this point, although I think it doesn't go far enough in calling out the incomplete picture of Rust implied by the original quote.)

    [1]: http://blog.rust-lang.org/2015/04/10/Fearless-Concurrency.ht...

  • pekk 10 years ago

    I have a vague question: how can you avoid putting emphasis on memory management, to the extent Rust does, without introducing mandatory garbage collection?

    • tormeh 10 years ago

      My understanding is that Rust is, to be wildly inaccurate, kind of like a language without a heap. Normal languages manage stack memory without GC. Rust kind of does the same: When deleting a stack frame, Rust deletes the objects created when on that stack frame, except when a reference is returned by the scope corresponding to the frame, in which case the "ownership" of the heap object is passed to the frame under the deleted-to-be frame.

      Sort of. Don't cite me.

    • firebones 10 years ago
yakcyll 10 years ago

For a C++ developer, Rust introduces a lot of seemingly arbitrary rules and constraints on how data can be managed, moved around and referenced. In order to develop things that employ a lot of composing, one has to either make the code nigh unreadable with tons of unnecessary chaining (which is unavoidable, since simple dereferencing and assigning a value of a field in a structure to a variable means the structure is now borrowed and you can't reference the field nor the structure until the variable goes out of scope; please, for the love of all that is holy, prove me wrong!) or the entire data model has to be rethought with those rules in mind. Not sure about others, but I sure as hell still have a lot of trouble wrapping my head around boxes, mutability and lifetimes; maybe I'm making some fundamentally flawed assumptions trying to draw similarities between C++ and Rust, but those issues are showstoppers for me for now.

  • geofft 10 years ago

    simple dereferencing and assigning a value of a field in a structure to a variable means the structure is now borrowed and you can't reference the field nor the structure until the variable goes out of scope; please, for the love of all that is holy, prove me wrong!

    This is only partially true. If you hold a mutable reference to a field in a structure, you can't get a reference to the entire structure. (Think of a mutable reference as a read-write lock, because that's what it is, just at compile time / type level instead of at runtime.) However, you can get a mutable reference to other fields in the structure. And an immutable reference to a field (analogous to a read-only / shared lock) does not prevent other immutable references, so you can totally get a reference to the structure while a reference to one of its fields is outstanding.

    Here's an example of this on play.rust-lang.org: http://is.gd/ySSsex

    That compiles and runs with the extra scope around the mutable borrows. If you comment out that scope, then yes, it won't compile.

    My experience, coming to Rust from C++ and C, is that a lot of real-world C++ and C code is imprecise about mutability and shared references, and relies on the programmer not doing anything particularly weird. It's true that in this example, nothing would go wrong by omitting the braces because the references g and h aren't actually used. But in larger and legacy codebases, it's very easy to forget the mutability rules that were in the head of the previous programmer. So directly porting C++ code is going to be annoying, but that's mostly because the hard work is figuring out what was implicit in the C++.

  • steveklabnik 10 years ago

      > seemingly arbitrary rules
    
    Most of them are about Rust's core guarantee: data race freedom. Some of them are due to a certain conservativeness of any static analysis, and may be relaxed in the future.

      > for the love of all that is holy, prove me wrong
    
    It depends on exactly what you're doing. There are always ways to get around things, but it can depend on knowing Rust and its standard libraries well. As a younger language, some patterns are still being developed, and aren't always as obvious as they could be. We'll get there...

    Rust is certainly a different language, and if you try to port C++ code directly over, you may have problems. Such is life. :)

    • Manishearth 10 years ago

      > Most of them are about Rust's core guarantee: data race freedom

      IMO this is just a part of it (and I think you agree, based on previous conversations). The actual thing is that the rules enforce a discipline about data, similar to the discipline in functional languages (except here it's allowing sharing XOR mutation instead of forbidding mutation entirely). This discipline gets us many things -- memory safety, safety from iterator invalidation-y things (there's a whole class of memory safety bugs that happen when you modify the exterior of a things whilst holding a pointer to the interior -- from iterator invalidation to invalidating pointers to a vector after truncation to invalidating enums), and clarity in code. Whilst the chronology of it's design may not be such, I personally look at data race freedom as something we got for free from this discipline, instead of the core focus of it.

      • dbaupp 10 years ago

        I strongly disagree: the goal with Rust is to offer safe, low-level programming, not to be a test-bed (or whatever) for some programming paradigm. The "discipline" is just a tool to reach the goal. You can see this in the evolution of Rust: the goal hasn't changed, but the tool used to (try to) reach it has. (I know that you mention ignoring the chronology, but ignoring the intent doesn't make sense.)

        Put another way: Rust isn't aiming to be top of the pack in terms of enforcing a certain programming style, where as it is aiming to be top of the pack in terms of safe systems programming. (It might happen to be the best language for the former, but that is a consequence of the latter, not the other way around.)

        • Manishearth 10 years ago

          You misunderstand me: I don't disagree that Rust is all about safe systems programming. I disagree that "data race freedom" is Rust's (only) core guarantee, and I disagree that the "seemingly arbitrary rules" are about "data race freedom". They're about so much more, since the same rules get us memory safety as well, among other things.

          I don't think that Rust is trying to test out a programming paradigm or whatever, I'm saying that these "seemingly arbitrary rules" get us a lot of things, by proxy of a certain paradigm, and reducing it to "data race freedom" (when it's so much more) is something we should avoid.

          (My comment seems to focus on the discipline, I was just using it as a proxy for all of the things it gets us)

          • dbaupp 10 years ago

            As we discussed on IRC, "data race freedom" is equivalent to guaranteeing memory safety, and so, in a kind-of pedantic way, data race freedom is the core guarantee. That said, the original comment would've been better phrased as "one of Rust's core guarantees".

            Furthermore, I still think the best phrasing of the rules is for that guarantee: if a rule is removed one can usually construct fairly simple programs that have data races/memory unsafety. Of course, it is definitely true that the arbitrary rules have other benefits, but if there was a simpler scheme that gave the core memory safety without the other things, I think Rust would've adopted it.

    • yakcyll 10 years ago

      Definitely! I'm just hoping for this 'aha!' moment, since it just feels like black magic for me.

      I think conservative approach to fundamentals is a great way to build a robust language and the way it's presented to me suggests that's one of the objectives; however, for an outsider with experience in other, more lenient (and, obviously, bug-prone) languages, those constraints might appear too restrictive. I believe it's a transitional feeling though, hence calling them 'seemingly' arbitrary.

      • steveklabnik 10 years ago

        Totally. I'm actually re-doing all of the docs on this stuff right now, I hope that the next iteration will maybe make it easier to grok. We'll see!

  • Manishearth 10 years ago

    ... It takes some getting used to. If you've programmed in a functional way before, try shifting perspective in that direction a bit. Rust isn't pure functional, and pure functional programming won't work well in Rust, but the style of programming has some similar parts.

    It's a really bad idea to try and write stuff in a "C++ way" with tons of mutation, Rust encourages a rather different discipline in handling data which is at odds with the regular C++ style of programming. But this takes time to pick up. Once you've programmed with it for a while it feels pretty natural, though, especially since it's very easy to reason about data in this model.

    Here's why Rust has this model: http://manishearth.github.io/blog/2015/05/17/the-problem-wit...

    As geofft mentioned below, you can get mutable references to multiple fields if you want.

    In more complex situations, use Cell<T> (for copyable types, this is zero cost though it can prevent some optimizations) or RefCell<T> (this works for any type, but has a slight cost) for more fine-grained mutability control. You shouldn't need these often, but they exist

eximius 10 years ago

"No, you don't have to learn monads."

Ha! This is ironic because a present discussion over some syntactic sugar (maybe more) to make Rust error handling feel more part of the language and more ergonamic may be ad-hoc monads. Not that the programmer needs to know that - it's just something that should happen to play nice in the rest of the Rust type ecosystem

  • M2Ys4U 10 years ago

    I was under the impression that `Option<T>` and `Result<T, E>` were monads.

    • saurik 10 years ago

      What makes monads in Haskell interesting is that someone identified them as a pattern, generalized their usage, and then syntax was added to the language that lets you compose them in a natural manner. Sequential execution itself "is a monad", but in most languages we express that using something as simple as ";" or "\n": Haskell effectively generalized the idea of statements to support anything that is monadic, which is why identifying something as a monad ends up becoming so interesting in Haskell as opposed to many other languages.

      • pcwalton 10 years ago

        And Haskell gave up rich control flow (break, continue, early return) by doing so. If you trace through what having those statements means for monads as a first-class concept, you find that the situation becomes very much not that simple.

    • mafribe 10 years ago

      MONSIEUR JOURDAIN: Oh, really? So when I say: "x := x+1" and "throw new Exception” is that monadic?

      PHILOSOPHY MASTER: Most clearly.

      MONSIEUR JOURDAIN: Well, what do you know about that! These forty years now I’ve been using monads in programming without knowing it!

          -------------------------------
      
      With many apologies to Molière, many things are monadic including state and exceptions. Most programming languages introduce them as first-class core concepts rather than as monad instances. Hence you can use them innocently, without realising that they are monadic.
    • u320 10 years ago

      Yes but the Rust type system cannot express monads, so they aren't monads in the type sense (they don't implement a specific Monad trait).

shams93 10 years ago

I'm slowly learning rust. Ive worked with c and jni in android for sound apps but now Im ignoring my reactions over the weird parts of rust so i can use it to builda killer music application for raspberry pi

  • kitd 10 years ago

    If it helps, I've called Rust over JNI. Fairly easy in fact though I recommend judicious examination of examples on the web first.

    Cargo is also very helpful in this regard.

  • firebones 10 years ago

    Any references/repos to learn from?

jbandela1 10 years ago

Wow, this is the first post I have ever read that even kind of implied that Andrei Alexandrescu was a Blub programmer.

Part of being a Blub programmer is that you don't even think about the issues. In regards to the weird features brought up, the underlying issues behind these features have been in the C++ consciousness for some time. Below are some talks and resources covering at least some of these issues.

Sean Parent - Inheritance is the Base Class of Evil - https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&c...

Herb Sutter - You don't know const and mutable - http://herbsutter.com/2013/01/01/video-you-dont-know-const-a...

Andrei Alexandrescu - Systematic error handling in C++ - https://channel9.msdn.com/Shows/Going+Deep/C-and-Beyond-2012...

Herb Sutter - Writing Good C++ by Default - https://www.youtube.com/watch?v=hEx5DNLWGgA

Andrew Sutton - Generic Programming with Concepts Lite - https://www.youtube.com/watch?v=qwXq5MqY2ZA

One of the things that helps with avoiding "Blubness" in C++ is the significant interest in languages such as Haskel (which is not considered a Blub language by anyone except Agda programmers) and in applying the techniques and insights where possible to C++ whether through writing new libraries (see for example Fit by Paul Fultz II -https://github.com/pfultz2/Fit) or through new language features (see this post by David Sankel - http://davidsankel.com/uncategorized/c-language-support-for-...)

Finally, is also interesting that Paul Graham's blub paradox is being brought up in regards to Rust, C++, and D. The Paul Graham article is in large part talking about the power of meta-programming. In this regard, D and C++ are significantly more powerful in that regard. Features like higher kinded types (template templates), variadics, and non-type template parameters help in this matter. When you can write a function that can generically work with a tuple with any number and type of parameters, you can do some pretty neat stuff. For some examples take a look at Boost.Hana by Louis Dionne (http://boostorg.github.io/hana/). In this regards, Rust is actually the Blub compared to D and C++.

  • pcwalton 10 years ago

    C++'s templates are untyped. Rust's templates are typed. Most people aren't aware of the difference, and they naturally think that templates "have to work" like the ones in their favorite language (dynamically typed if coming from C++ and D, and statically typed if coming from Java, C#, or most other languages). But the fact that Rust and C++/D picked different sides of the tradeoff is the key source of the differences between them.

    C++ and D programmers, like you (and Andrei), look down on Rust generics and give examples of all the things that you can't do with Rust generics that are easy to do with C++ templates. But there's an equally strong counterargument, in that Rust generics never give errors at template expansion time and are guaranteed to expand to valid code. This makes code easier to understand, improves the experience for users of your generics, and also simplifies the implementation, leading to potentially better compile times (since you typecheck once instead of after every template expansion). Of course, this is a tradeoff: it's more work for us to implement the features necessary to do the kinds of sophisticated metaprogramming you see in C++ and D, and there will always be some things you can't do in Rust that are easy in C++ and D. But that isn't a slam-dunk argument for untyped templates vs. typed generics any more than easy reflection is a slam-dunk argument for dynamic typing like Python vs. static typing like Java.

  • djur 10 years ago

    > In this regards, Rust is actually the Blub compared to D and C++.

    I think this demonstrates a significant weakness in Blub as a concept: there is not even a partial ordering of languages by power. The essay only works because Graham picks the two sides of the debate: Lisp, which Graham believes to be the most powerful of languages, and Blub, a theoretical language that can be stipulated to be less powerful than Lisp in all ways.

    Outside the essay, "blub" only exists as a slur for a despised language or an insult for another programmer, and it's only useful as a way to start arguments.

  • steveklabnik 10 years ago

      > In this regards, Rust is actually the Blub 
    
    I'm not so sure. We are aware of the features that they have; we just prefer the strongly-typed versions to the stringly-typed[1] versions.

    We do desire more meta-programming features, and they will happen. Like all decisions, we don't want to rush into them.

    1: This is not _entirely_ accurate, but I'm slightly at a loss for how to exactly characterize this at this particular moment. Rust's metaprogramming guarantees that you always generate valid Rust code, D's does not.

    • jbandela1 10 years ago

      The last statement was more in regards to the Blub definition implied by the article. Of course, people who are immersed in programming language theory are not Blub programmers - they are aware of what is possible, but are also aware of the inherent tradeoffs.

      With regards to Rust, do you have any idea when more meta-programming features like variadics and non-type template parameters might be available in the language (are we looking at months, years, or decades)? Rust, has a lot of features that really interest me, but seeing the tuple serialization code brought back bad nightmares of simulating variadic templates using macros in C++ before I had a compiler that supported C++11 variadics. To me, at least personally, it felt like a step backward from C++14, and kind of curtailed my enthusiasm for doing a deep dive into the language. My test for the power of a language's type manipulation is how easy is it to write an implementation of apply(Function f, Tuple t) which will call f with the values of t. I would be most interested to see how Rust will implement this kind of metaprogramming.

      • steveklabnik 10 years ago

        Yeah, I agree with my sibling comment above that Blub is kind of a weak concept for this reason.

        It's hard to say because the work for those features hasn't even been started; the MIR refactoring is still underway. Once that's done, RFCs for this stuff will start to appear, and we'll have a better idea of overall schedule. I would say that the current schedule is "longer than months, shorter than a few years".

        I myself _really_ want higher kinded types, but at the same time, I would rather wait and do it right than rush and regret thing slater. We have a solid language as it is; the need to get these more advanced features is not particularly urgent, in my opinion. I like to think on the long scale when it comes to the language: if it's going to be around 40 or 50 years, we're in year one. There's plenty of time.

      • pcwalton 10 years ago

        > My test for the power of a language's type manipulation is how easy is it to write an implementation of apply(Function f, Tuple t) which will call f with the values of t. I would be most interested to see how Rust will implement this kind of metaprogramming.

        That's kind of a weird litmus test of the power of the language's type manipulation: it only applies to languages where functions take multiple arguments, it's a pretty niche use case (since the workaround in Rust is straightforward), and there's nothing particularly sophisticated about variadic generics (what you need to solve the problem). I could equally say that my litmus test of a language's generics system is whether the compiler prevents errors during template expansion.

        Anyway, to answer your question: that's really easy in Rust, as long as you're on nightly. The FnMut trait (and friends) allow you to call functions with tuples as arguments. https://doc.rust-lang.org/std/ops/trait.FnMut.html

    • mst 10 years ago

      Is that mostly a faster feedback loop and better errors thing? It seems like so long as the generated code doesn't get as far as compiling, it doesn't make that much of a difference?

      (this could easily be a stupid question; I know I've come across as condescending to you before by mistake and if I've somehow done it again please believe that I meant to come across as genuinely curious :)

      • pcwalton 10 years ago

        There are a number of benefits to concepts:

        - They make namespacing of functions easier, eliminating the need for C++'s "argument-dependent lookup". The issues here are somewhat subtle and would take a lot of space to explain. But the end result is that we can remove a massive amount of confusion by getting rid of ADL.

        - Error messages are much better, because the insides of templates never leak to users of the template.

        - Typechecking is simplified, because we only have to typecheck each template once, at the time of definition, as opposed to repeatedly typechecking it from scratch every time it's instantiated. This, in theory, allows compilation to be faster.

        • mst 10 years ago

          > Error messages are much better, because the insides of templates never leak to users of the template

          This is unequivocally a good thing - I think maybe my disconnect here in how excited I am compared to others is that I'm comparing it to the experience of debugging lisp macros and everybody else is comparing it to the bottomless pit of despair that is C++ template errors ;)

      • steveklabnik 10 years ago

        Not at all!

        Yes, to me, it's largely about better errors and such. If th generated code is wrong, it won't compile, so it's not _that_ level of bad. But this can't happen in Rust: http://tgceec.tumblr.com/

        • mst 10 years ago

          Now I want to see an article that compares the error messages from rust and D metaprogramming ... though admittedly, at least half of this is because you could call said article "D missed nosejob day".

      • Manishearth 10 years ago

        Note that with bounded polymorphism you get clear API boundaries too. With templates you may have to clearly document what kind of type is allowed in.

        There's also the danger of something compiling where it shouldn't.

    • u320 10 years ago

      I would go one step further and say that those features in Rust (and ML, Haskell etc) aren't even metaprogramming. So D uses metaprogramming to make up for a weaker type system.

    • Manishearth 10 years ago

      I like to call C++ templates "structurally typed", since you can get some degree of that from SFINAE and composing templates together. They're more pattern-matching based than type-based. This is reminiscent of how Go auto-impls interfaces, really.

  • GFK_of_xmaspast 10 years ago

    It's always easier to see the blub in someone else's language and not in our own.

sago 10 years ago

How very patronizing. There's a tendency we all have to assume that someone would agree with us, if they weren't so ignorant/stupid/naive. None of us want to feel that we'd agree with them if only we understood.

Seems this is the programming equivalent. Programmer X turns their nose up at my pet language Y. It can't be because of me, it has to be their naivitee/ignorance/lack of experience/bias, etc, etc.

That the article was a big "you're ignorant" to Andrei Alexandrescu, of all people, was telling.

pklausler 10 years ago

Some programmers can write BASIC in any language. But on the up side, some programmers can write Haskell in any language.

Keyboard Shortcuts

j
Next item
k
Previous item
o / Enter
Open selected item
?
Show this help
Esc
Close modal / clear selection