News for hackers. Stuff that matters.
Re:Introducing MIR by kibwen on Wednesday April 27, 2016 @12:24PM (#11581863)
I'm incredibly psyched for MIR. It'll represent the first conceptual "leap" for the language since Rust 1.0, checking off (or at least unblocking) a ton of the improvements that we've had in mind for years now (the list in the OP is hardly comprehensive!).

It's also interesting that Swift, another LLVM-based project, has also transitioned to using their own language-specific intermediate representation (SIL). I think it's fascinating that, despite the availability of a robust and mature pluggable language backend, two professional languages independently decided that they needed another layer of abstraction between AST and LLVM IR. Not sure if this should be interpreted as a bug report against LLVM IR, or if it possibly represents a future trend in compiler design.

EDIT: I should also mention that MIR has been available on play.rust-lang.org for a while, if anyone would like to play with it in their browser: https://play.rust-lang.org/?gist=fee8ccf28bae2c89107d&versio...

Re:Introducing MIR by nostrademons on Wednesday April 27, 2016 @12:54PM (#11582181)
It's been pretty common for compilers to require 3 different intermediate representations (parse tree, MIR, and LIR). My copy of Advanced Compiler Design and Optimization [1] (over 10 years old at this point) lists the 3-IR architecture on page 8. It references Sun's SPARC compilers, DEC's Alpha compilers, Intel's x86 compilers, and SGI's MIPS compilers as implementations that use it.

What has changed are the boundaries. Traditionally, semantic analysis (including typechecking) operated on the parse tree, which resembled the human-written language extensively. Optimization operated on MIR, then it'd be lowered to an architecture-specific LIR via register allocation and instruction selection, and another round of optimization (instruction scheduling, etc.) would be applied. The purpose of all of this was to provide multiple language front-ends on top of a single compiler. In the 80s and 90s, compilers were often written by the hardware vendor, so they would tightly optimize the MIR and LIR for their own architecture, and use the parse-tree => MIR lowering to support multiple surface languages.

LLVM chose a LIR that's closer to what many compilers had been using as MIR, and then moved the optimization passes into the LIR, and hid the architecture-specific backends within the LLVM project itself, out of the eyes of language designers. It could do this because of open-source: with a shared body of compiler code owned by everyone and gradual consolidation of the hardware market, it became easier to contribute your backend to LLVM than to maintain your own compiler stack and fight for adoption. (GCC actually had a fairly similar architecture first, but the GCC IR was very difficult to comprehend if you weren't a GCC maintainer, which made it impractical as a compilation target for outside projects. They generated C code instead and let GCC compile it.) That in turn made it much easier to write a compiler and experiment with language design, since you only had to figure out how to translate your language to LLVM's IR rather than work out the details of scheduling and register allocation. That, in turn, allowed greater complexity in language features: Swift and Rust have language features that go beyond what cutting-edge research was <10 years ago, and do so in a production language that you can use now. And so it's not surprising that they're now re-introducing a MIR to manage the additional complexity introduced by the new language features.

[1] http://www.amazon.com/Advanced-Compiler-Design-Implementatio...

Re:Introducing MIR by pcwalton on Wednesday April 27, 2016 @01:22PM (#11582444)
If you count the intermediate IRs that LLVM has, then Rust actually now has many more than three IRs: AST, HIR, MIR, LLVM IR, SelectionDAG, MachineInstr. Even before MIR, there were 5 IRs.
Re:Introducing MIR by Ericson2314 on Wednesday April 27, 2016 @03:12PM (#11583609)
Indeed, the more IRs, the better---structure your data to fit your task, not your algorithm to fit your data.
Re:Introducing MIR by infogulch on Wednesday April 27, 2016 @01:20PM (#11582426)
I tried to upvote you, but I fat-finger downvoted you instead. Sorry. :(
Re:Introducing MIR by BinaryIdiot on Wednesday April 27, 2016 @02:52PM (#11583433)
A slight side note: this is one of the most difficult parts with using Hacker News on a mobile device. I fat finger upvotes all the time! I wouldn't mind the ability to change a downvote to an upvote and vice versa, even if it was time limited so I could correct any incorrectly voted items.
Re:Introducing MIR by tetraodonpuffer on Wednesday April 27, 2016 @09:42PM (#11586049)
couldn't this be easily fixed by putting the downvote triangle on the other side of the time?

(upvote arrow) name xxx hours ago | parent | flag | (downvote arrow)

would make it less fat finger prone and still be pretty straightfoward to use (plus having downvote close to flag IMHO makes sense as well from a context perspective)

Re:Introducing MIR by odbol on Thursday April 28, 2016 @10:31PM (#11593418)
Could be easily fixed by one line of CSS to make the dang buttons larger, but apparently Hacker News can't be bothered to improve their shitty website.

EDIT: great community, shitty website.

Re:Introducing MIR by BinaryIdiot on Thursday April 28, 2016 @12:54AM (#11586617)
Yup that would work really well
Re:Introducing MIR by simcop2387 on Wednesday April 27, 2016 @03:30PM (#11583747)
Either that, or a way to hide the down vote on mobile. I hardly ever legitimately down vote so when i fat finger it on mobile it just makes me look like a jerk.
Re:Introducing MIR by MichaelGG on Wednesday April 27, 2016 @06:44PM (#11585213)
Except no one can see you did it, so it doesn't make you look like a jerk. A random downvote here and there shouldn't bother anyone. It's probably better off if we just realise this and never talk about it.
Re:Introducing MIR by nostrademons on Wednesday April 27, 2016 @07:01PM (#11585309)
Depends on context. I'm at +149 right now on the top-level comment, so one upvote that turned into a downvote isn't really a big deal. It could be pretty annoying if you've worked hard on a long comment and then it goes from 0 to -1 instead of +1 because of a fat-fingered downvote.
Re:Introducing MIR by spacemanmatt on Wednesday April 27, 2016 @03:28PM (#11583719)
I use the Android app Materialistic, and don't seem to have ui problems. YMMV.
Re:Introducing MIR by cyphar on Thursday April 28, 2016 @07:21PM (#11592623)
I use it too. The only problem is that the latest update broke the commenting (it only allows you to type one line). But I filed a bug report and it was fixed, so we just have to wait for the update. This is why I love free software. No begging in app comment sections.
Re:Introducing MIR by brynjolf on Thursday April 28, 2016 @03:01AM (#11586954)
I love that app so much. It is nearly perfect!
Re:Introducing MIR by iopq on Wednesday April 27, 2016 @04:50PM (#11584423)
I gotchu fam
Re:Introducing MIR by mietek on Wednesday April 27, 2016 @04:53PM (#11584450)
> Swift and Rust have language features that go beyond what cutting-edge research was <10 years ago

Such as?

Re:Introducing MIR by nostrademons on Wednesday April 27, 2016 @05:53PM (#11584890)
Type inference in the presence of OOP-style subtyping was largely considered to be impossible in 2005; there had been a lot of research results with System F:< and System Fw, along with a well-known undecidability result [1]. Attempts to introduce subtyping into research languages like Haskell and Ocaml gave us records [2] and objects [3], but neither of these were something that an ordinary mainstream programmer would want to use. Haskell's type system made it frustratingly easy to construct types that would force the typechecker into an infinite loop [4].

And now Swift not only allows these in a way that's familiar to existing mainstream programmers, it interoperates fully with Objective-C and offers additional features like polymorphic literals. And when polymorphic literals (previously allowed only by Haskell, and then not with user-defined types) makes typechecking take 12 hours [5], it's widely decried for being poorly implemented.

On the Rust end - the whole concept of the borrow checker was borrowed (sorry) from Cyclone [6][7], a research language of the early 2000s. I remember seeing it occasionally pop up on Lambda: the Ultimate [8] around 2004-2005, people seemed intrigued, but few people really took notice. Rust's big accomplishment is to generalize this to an "industrial strength" programming language, figuring out all the corner cases around mutability, traits, move-semantics, boxes, etc. that you need for this to work in real programming.

[1] http://repository.cmu.edu/cgi/viewcontent.cgi?article=3059&c...

[2] http://research.microsoft.com/en-us/um/people/simonpj/Haskel...

[3] https://realworldocaml.org/v1/en/html/objects.html

[4] https://downloads.haskell.org/~ghc/latest/docs/html/users_gu...

[5] https://www.reddit.com/r/programming/comments/4givdg/go_home...

[6] http://www.bennetyee.org/ucsd-pages/Courses/cse227.w03/hando...

[7] https://www.cs.umd.edu/~mwh/papers/ismm.pdf

[8] http://lambda-the-ultimate.org

Re:Introducing MIR by pcwalton on Wednesday April 27, 2016 @06:03PM (#11584955)
> On the Rust end - the whole concept of the borrow checker was borrowed from Cyclone

Not really. That's the lifetime system, which is not the same thing. "Existential Types for Imperative Languages", also by Dan Grossman, explains more of the motivation, but the borrow check is a hybrid of the two solutions he presents.

Borrowing itself is something with a long history, but the whole "unique loan paths" thing makes Rust's solution distinct from a lot of the stuff you find in the research literature.

Re:Introducing MIR by tomp on Wednesday April 27, 2016 @06:50PM (#11585238)
> Type inference in the presence of OOP-style subtyping was largely considered to be impossible in 2005

Type inference in a OO language is still considered, if not impossible, at least very impractical. Swift, Scala and Rust avoid most algorithmic complexity and ambiguity by mostly supporting only type propagation instead of type inference, and thus require annotations on function parameters.

Re:Introducing MIR by nostrademons on Wednesday April 27, 2016 @07:34PM (#11585476)
The big innovation there is in realizing that's enough. When I was into language design from 2004-2007, language designers usually assumed people wanted full global type inference. It turns out that local type propagation is an effective 80/20 solution for most practical programming tasks, which opened up a lot of hybrid type systems that would've been far too complex before.
Re:Introducing MIR by pshc on Thursday April 28, 2016 @01:25AM (#11586706)
Yes. A blessing in disguise. In hindsight, global type inference seems too unstable. Too much action at a distance; it's hard to evolve a codebase when local changes cascade. Type annotations keep things grounded.
Re:Introducing MIR by sklogic on Thursday April 28, 2016 @06:02AM (#11587603)
Nemerle had quite an interesting solution to this problem back then.

http://research.microsoft.com/en-us/um/people/moskal/pdf/msc...

Re:Introducing MIR by mietek on Thursday April 28, 2016 @11:43AM (#11589694)
Yes. It’s worth pointing out that this is the author’s MSc thesis, submitted in 2005.
Re:Introducing MIR by jeltz on Wednesday April 27, 2016 @08:46PM (#11585844)
What about Crystal? It has quite extensive type inference.
Re:Introducing MIR by yokohummer7 on Thursday April 28, 2016 @01:00AM (#11586634)
Unfortunately they also had to narrow down the scope of type inference recently. IIRC type annotations are now mandatory for class-level variables (member variables). This hindered the "Ruby-like" feeling, but they had to give up global type inference because it costed too much memory in some cases. I got an impression that global type inference is difficult (or, costly) in general.
Re:Introducing MIR by humanrebar on Thursday April 28, 2016 @07:34AM (#11587980)
I'm not sure I consider Rust to be object oriented.
Re:Introducing MIR by aseipp on Wednesday April 27, 2016 @06:20PM (#11585058)
> Haskell's type system made it frustratingly easy to construct types that would force the typechecker into an infinite loop [4].

It's more akin to C++ templates, where the type checker only has a bounded number of reductions it will do before it gives up. Aside from writing something that really is infinite and a limit of trillions of reductions - which wouldn't really be a useful program - it ends up as a type error as you'd expect. This also only happens with -XUndecidableInstances, which frankly isn't really one of the most common extensions, I'd say.

That said, in practice, most Haskell programmers seem to largely consider subtyping a misfeature anyway, and approximations of it elsewhere in the ecosystem use things like RankNTypes to give a 'feel' for subtyping where you can do things like "use any instance of a more general base type, in place of that type, right here". The infamous lens library does this to great effect.

> previously allowed only by Haskell, and then not with user-defined types

I don't know what you mean here - Haskell has, until recently, never allowed overloaded literals for certain syntactic forms, like lists. For the other cases, though, like numerics, you have always been able to have polymorphic literals, which can be instantiated to user-defined type. The most general type of `1` by itself with no defaulting is `1 :: Num a => a`, and there's certainly no problem with instantiating `a` to whatever user-defined type you have, providing it can sensibly be constructed from a base-10 decimal value (meaning, you have a function `toInteger :: Integer -> a`)

These days, lists are also syntactically overloadable by a similar convention, through value polymorphism/type classes.

Re:Introducing MIR by pjmlp on Thursday April 28, 2016 @02:27AM (#11586862)
Meanwhile companies like Google invest their money in languages that were already known to be possible in 1968.

http://cowlark.com/2009-11-15-go/

Re:Introducing MIR by Ygg2 on Thursday April 28, 2016 @05:45AM (#11587528)
I like Rust, but there is nothing wrong with Go (I think their decision to not have generics does have some merit). They just took trade-offs they needed. Nothing wrong with that.
Re:Introducing MIR by pjmlp on Thursday April 28, 2016 @06:06AM (#11587617)
I did like Oberon a lot, and appreciate Oberon-2 influence on Go, but I think there is a lost opportunity in a company like Google sponsoring such a design, when it could have done so much more helping advancing the state of art for mainstream developers.

In that regard, Apple and Microsoft do so much more to help developers improve their skill sets, given the programming languages and tools that they have brought into the market.

However, I do advocate Go for the use cases where developers still make use of C for user space applications, without any real need for C's low level features.

Also do believe that Go can actually be used for systems programming, even if not all scenarios from systems programming like for example, 8 and 16 bit embedded processors, can be covered.

The language is similar enough to Oberon and Limbo for it to be possible, just needs someone to write a bare metal runtime.

Re:Introducing MIR by shawn-butler on Wednesday April 27, 2016 @12:54PM (#11582186)
There is a long tradition of type-directed compilation. Haskell compilation system refers to it as the simplifier or "middle end".

The parsing and type-checking produces a IR known as 'Core'. The middle-end optimizes it as a series of source-to-source transformations on Core code.

The back end of the compiler transforms Core code into an internal representation of a C dialect called C--, via yet another intermediate language STG (short for "Spineless Tagless G-machine").

Finally, the C-- code output can either be printed as C code for compilation with GCC, converted directly into native binary, or converted to LLVM virtual machine code for compilation with LLVM. Any output is linked against the Haskell runtime.

The innovation would come in creating the optimizations in the middle-end that could not be possible in the LLVM backend. Proof is in the pudding. Introducing another layer without any meaningful results is how projects bloat (NIH syndrome).

There is a LLVM backend that implements most if not all of the GHC "middle-end" optimizations[0] and should provide you with details/context you are seeking.

[0] http://blog.llvm.org/2010/05/glasgow-haskell-compiler-and-ll...

Re:Introducing MIR by Tehnix on Wednesday April 27, 2016 @01:13PM (#11582362)
>The innovation would come in creating the optimizations in the middle-end that could not be possible in the LLVM backend

>There is a LLVM backend that implements most if not all of the GHC "middle-end" optimizations

I'm not sure I follow, are you saying that the optimisations are possible or not in LLVM? I don't think the LLVM optimisation passes can make guarantees such as is needed for (say) the rewrite rules that rely heavily on purity.

Re:Introducing MIR by aseipp on Wednesday April 27, 2016 @02:53PM (#11583448)
LLVM doesn't ever even bother with rewrite rules. That's done substantially earlier in the compiler, at the Core phase (rewrite rules are 'just' equational reasoning optimizations that the compiler is aware of, so it works roughly at the level of the program you write, vs any more complicated intermediate form.)

There is still some inlining/smarts going on at the LLVM level, obviously, but it's nowhere near as aggressive as it is at the Core level in GHC. And obviously rewrite rules are user-definable - so they kick in much earlier. (As a side note, we actually spit out pretty optimized LLVM code from the C-- backend, in such a way that only some of LLVM's heaviest optimizations make a difference).

There are some specific optimizations that are simply not possible for LLVM in the general case and are better handled before conversion (for example, C-- at one point essentially gets CPS transformed in a way which LLVM cannot 'see through', and by that point you've lost the opportunity to do a number of simpler optimizations like basic constant propagation, while it's trivial to do earlier). But that's mostly the same in any compiler, and not unique to GHC...

Re:Introducing MIR by shawn-butler on Wednesday April 27, 2016 @01:17PM (#11582391)
Please read the link I provided and search the page for "Problems with the backend"

...There is one major issue remaining with the LLVM backend that I currently know of, its inability to implement a optimisation used by GHC called 'TABLES_NEXT_TO_CODE' (TNTC)...

Re:Introducing MIR by aseipp on Wednesday April 27, 2016 @02:48PM (#11583399)
That was fixed in LLVM 3.6 in a more general way, by one of my coworkers, Ben. http://reviews.llvm.org/D6454

The prologue support directly subsumes previous behavior (the `prefix` form) and is more flexible, and with it, GHC doesn't have to rely on shuffling assembly output in order to achieve TNTC.

Re:Introducing MIR by eloisius on Wednesday April 27, 2016 @01:12PM (#11582344)
I can't wait to see improved borrow checking! I'm not sure it'll fix this specific case, but I often find myself needing to introduce a scope just to hint the borrow checker into doing the right thing. For example:

    fn handle_message(&mut self, find_node_query: messages::FindNodeQuery) {
        let origin = node::UdpNode::deserialize(find_node_query.get_origin());
        let target = Address::from_str(find_node_query.get_target());

        {
            // Borrow self.routing_table first time
            let nodes: Vec<&Box<node::Node>> = self.routing_table.nearest_to(&target);
            let response = Message::Response(
                self.transaction_ids.generate(),
                Response::FindNode(&self.self_node, nodes));
            origin.send(response.serialize());
        } // Done borrowing self.routing_table here

        // Borrow self.routing_table again
        self.routing_table.insert(origin);
    }
edit: upon digging into the details, it looks like it may: https://github.com/rust-lang/rfcs/blob/db66dd2039b10b7590840...
Re:Introducing MIR by steveklabnik on Wednesday April 27, 2016 @01:15PM (#11582370)
Yes, this is "non-lexical borrows"/"SEME regions", and is exactly what MIR will enable. Or at least, is one of the things :)
Re:Introducing MIR by Shoop on Wednesday April 27, 2016 @01:52PM (#11582777)
Could we see non-lexical borrows within the year?
Re:Introducing MIR by kibwen on Wednesday April 27, 2016 @02:50PM (#11583414)
I think it's too early to say. The devs have assured me that MIR itself will land within the year, but beyond that point I think that non-lexical borrows might be out-prioritized (though just barely so) by incremental recompilation.
Re:Introducing MIR by steveklabnik on Wednesday April 27, 2016 @02:07PM (#11582936)
I'm not sure I can say for sure when they'll be ready, as MIR isn't 100% done, and they're built on top, so it's tough. There's also the difference between "lands in nightly" and "lands in stable", which could be some time for a feature so large.
Re:Introducing MIR by tychuz on Wednesday April 27, 2016 @07:11PM (#11585360)
Every time I see rust news, I feel the urge to learn this language. But, thankfully, someone posts some random snippet. :-) Java is a beautiful language compared to this.
Re:Introducing MIR by Sacho on Thursday April 28, 2016 @02:36AM (#11586893)
My only complaint is the mix between snake_case and PascalCase. I tried removing it(in favor of snake_case, but you could probably get a similar result if going full PascalCase), and it looks much better(no guarantee it has the same semantics, I've never worked with rust):

     fn handle_message(&mut self, find_node_query: messages::find_node_query) {
        let origin = node::udp_node::deserialize(find_node_query.get_origin());
        let target = address::from_str(find_node_query.get_target());

        {
            // Borrow self.routing_table first time
            let nodes: vec<&box<node::node>> = self.routing_table.nearest_to(&target);
            let response = message::response(
                self.transaction_ids.generate(),
                response::find_node(&self.self_node, nodes)
            );
            origin.send(response.serialize());
        } // Done borrowing self.routing_table here

        // Borrow self.routing_table again
        self.routing_table.insert(origin);
    }
Re:Introducing MIR by kibwen on Thursday April 28, 2016 @04:41AM (#11587303)
It sure does look more like C that way (if that's something you're into), but that also makes it harder to scan for types at a glance.
Re:Introducing MIR by pcwalton on Thursday April 28, 2016 @06:04PM (#11592247)
Rust used to work that way, but it was changed primarily to visually distinguish between enumerated variant names and variable bindings in patterns. e.g. match foo { none => ... } and match foo { non => ... } having completely different interpretations was confusing.
Re:Introducing MIR by jeffdavis on Thursday April 28, 2016 @01:56AM (#11586782)
Can you please post an equivalent Java program for comparison?
Re:Introducing MIR by baq on Thursday April 28, 2016 @01:12AM (#11586673)
Java is also a completely different language. Each tool has a different purpose.
Re:Introducing MIR by dschiptsov on Thursday April 28, 2016 @12:28AM (#11586555)
Exactly. There are few fundamental principles which have been neglected in order to provide way too many features (a kitchen sinc syndrome).

For example, "do not create unecessary entities" maxim, which, it seems, is central for good language design (ML, Scheme, Haskell, Smalltalk, Erlang, Golang are small languages, the first three are even standardized). As long as we violate this genetal rule we end up in a mess like CL, C++, and of course Java as a peak of absurdity).

The meme that "implementation languages must be feature rich" does not hold beyond certain limits, and even Rust designers have realized that there must be certain restrictions. In fact, C - the oldest and most common implementation language is still alive and well (despite all the mess other people made of it since it left Bell Labs).

The best illustration I know is refusal of the Golang designers to complicate (to ruin the balance of simplicity and elegance with expressiveness, which is the most difficult to attain - every poet or artist will tell you that - to create an unbalanced pile of features is way easier) the language by adding generics in the language and runtime. For them interfaces (duck-typing) is good-enough).

"Explicit is better than implicit" is also a naively wrong maxim. Verbosity is bad. Period. Every good writer I know is non-verbose. Meaning behind words is what makes a good literature, not long words or elaborate passages half page long (ironically, common men think exactly opposite is true). Convention over configuration (evolved defaults instead of explicitly spelling every single rule over and over again) is the same notion from a different perspective.

Here comes Scheme - the greatest mostly-functional small language with balanced defaults, cohetent semantics (almost like in math), and unmatched expressiveness with almost no syntax at all (expressive power comes from coherent defaults that everything is an expression, everything (including lambdas) is a first-class value referenced by symbol, lexical scooping, very few standard special forms and the ability to create new ones.) as an good example. Smalltalk and Erlang are another ones for the emphasis on message passing and, in case of Erlang - pure functionality and isolation - the way vastly complex biological systems has been implemented by evolution.

So, those who have seen highly refined languages like Haskell or Scheme or Smalltalk would never be fooled by "features". The meme that "each project must first agree on which subset of C++ it would restrict itself to" is another good illustration. Rust, like Java, is already suffering from this kitchen sink syndrome, so the comment above is legitimate.

BTW, it seems that many of features should go from the language to sanitizers and checkers, like it is with clang tooling.

Re:Introducing MIR by AlisdairO on Thursday April 28, 2016 @10:00AM (#11588880)
> "Explicit is better than implicit" is also a naively wrong maxim. Verbosity is bad. Period. Every good writer I know is non-verbose. Meaning behind words is what makes a good literature, not long words or elaborate passages half page long

Good writing often allows (or even encourages) a reader to concoct their own inference of exactly what the author means. Witness discussions that last to this day of many ancient classics. Such ambiguity may be fine for writing, but it is obviously disastrous for large engineering projects.

That's fine - not all code is a large engineering project - but most of the people I know who work on very large code bases will take explicitness every time. And those are the kind of projects that Rust is aimed at tackling.

Re:Introducing MIR by dschiptsov on Thursday April 28, 2016 @11:47AM (#11589720)
Explicitly passing &self is lame. Haskell's implicit parameters are clever.)

Actually, the language fells Rubysh - a bit of syntax from here and there. Swift has much more refined and concise syntax, because they paid way more attention to details.

Patter matching on type constructors could have been taken from Haskell - it won't hurt.

Block syntax with where clause (why?) is really bad.

The syntax inconsistency and awkwardness aren't major issues, but it is telling.

Re:Introducing MIR by pcwalton on Thursday April 28, 2016 @06:02PM (#11592231)
None of your examples make sense to me.

You say "explicitly passing self is lame" and then praise Golang for "feature restraint" when it does the exact same thing.

I don't know what "pattern matching on type constructors" means. You use the constructor syntax to pattern match in Rust.

There is no such thing as "block syntax with where clause". Where clauses go on signatures, not blocks. This is also the exact same syntax as Swift, which you praise for "more refined syntax".

Re:Introducing MIR by dschiptsov on Thursday April 28, 2016 @11:11PM (#11593554)
Golang is praised for attention to details and fair attempt to attain that kind of balanced mix of complementing each other features.

The principles, rather idealistically, are outlined here:

http://karma-engineering.com/lab/wiki/Bootstraping

Pattern matching is technically almost unchanged since Standard ML, but in Haskell the syntax is refined by perfectionists (in best possible meaning of this word).

Swift, obviously, trying very hard to look familiar for [Objective-]C (but not Java) programmers, and to follow the principle of less astonishment, produced much more concise syntactic choices, and the devil is in the details.

BTW, if one wants to see another example of carefully crafted language, there is PLOT

http://users.rcn.com/david-moon/PLOT3/

Re:Introducing MIR by pcwalton on Friday April 29, 2016 @01:50AM (#11593967)
This is very philosophical and also entirely unresponsive to my points.
Re:Introducing MIR by AlisdairO on Friday April 29, 2016 @09:45AM (#11595653)
> Explicitly passing &self is lame

Explicit passing of &self (or &mut self, or self) might be 'lame', but it also gives more clarity as to what the code is doing. I can't say it's ever once given me pause.

Re:Introducing MIR by kibwen on Thursday April 28, 2016 @04:45AM (#11587318)
Rust is emphatically not a kitchen sink language. If you believe otherwise, please explain what features you would remove without compromising safety or the notion of zero-cost abstractions.
Re:Introducing MIR by dschiptsov on Thursday April 28, 2016 @05:07AM (#11587386)
I don't believe in safety and zero costs. These are mere catchy memes.

I could only repeat my question: How Common Lisp or even more pragmatic Golang are less safe? I am not asking about Haskell or Erlang.)

Compile time error for trying to use an old binding/reference? Is this memory safety?

Re:Introducing MIR by nercury on Thursday April 28, 2016 @01:12PM (#11590394)
The engineering decisions are not based on beliefs. They are usually trade-offs. Safety in Rust has a very specific meaning clearly outlined in the official book. There are users who prefer it for certain tasks. The answer to your last question is also in the book.
Re:Introducing MIR by dschiptsov on Thursday April 28, 2016 @11:07PM (#11593534)
Why not state it here in a few simple sentences, like for a 5 year old? Clarity is usually an evidence for deep understanding. I hope I will be able to get it.
Re:Introducing MIR by pcwalton on Friday April 29, 2016 @01:53AM (#11593972)
Memory safety without garbage collection. (While still supporting dynamic allocation.)
Re:Introducing MIR by pcwalton on Thursday April 28, 2016 @06:11PM (#11592281)
Go is less safe due to the "Off to the Races" problem, but there's a legitimate debate as to whether that safety loss matters in practice.

Common Lisp and Golang use GC, which exacts a performance cost in some scenarios. Go also has highly dynamic semantics (e.g. with defer) which have unavoidable performance overhead, especially in an AOT compilation setting.

Re:Introducing MIR by pcwalton on Thursday April 28, 2016 @06:07PM (#11592265)
Do you have specific examples of Rust features you claim are unnecessary?

Rust would not work at all with the borrow check as a separate tool, by the way. It would be comically easy to write broken code.

Re:Introducing MIR by DannyBee on Wednesday April 27, 2016 @02:27PM (#11583158)
" Not sure if this should be interpreted as a bug report against LLVM IR, or if it possibly represents a future trend in compiler design."

Compilers have pretty much been the way (with the exception of GCC) since about 1975, if not earlier. :)

LLVM is deliberately low level. SWIFT uses a higher level IR because they want to do static analysis and language specific optimizations on it. This makes sense, LLVM's IR is not going to be good at that.

You could transmit metadata, but it's probably not a good architectural solution compared to progressive lowering of IR.

Re:Introducing MIR by steveklabnik on Wednesday April 27, 2016 @12:28PM (#11581913)
Re:Introducing MIR by kibwen on Wednesday April 27, 2016 @01:21PM (#11582431)
Fixed, and upvoted for the link. :)
Re:Introducing MIR by takeda on Wednesday April 27, 2016 @02:05PM (#11582912)
This is a common approach in compilers. It makes things more manageable. Each of the languages is simpler but has more constraints until you reach to the constraints that machine provides.

Here is example of compiler construction class: http://web.cs.ucla.edu/~palsberg/course/cs132/project.html

The mid languages were named after character in Winnie the Pooh, you can also see how factorial example looked in each stage.

Re:Introducing MIR by Someone on Wednesday April 27, 2016 @12:52PM (#11582167)
Re:Introducing MIR by kibwen on Wednesday April 27, 2016 @01:18PM (#11582402)
I believe that's a bit different, as Webkit entirely replaced LLVM with a new backend, whereas here Rust is still ultimately emitting LLVM IR, just with a new well-defined step in-between.
Re:Introducing MIR by majewsky on Wednesday April 27, 2016 @12:43PM (#11582097)
Not necessarily a future trend. When I took a class in compiler construction last semester, the professor considered it industry standard to use multiple (AFAIR he said "up to five") IRs in the same compiler/linker toolchain.
Re:Introducing MIR by kibwen on Wednesday April 27, 2016 @12:51PM (#11582161)
If we're looking at the full toolchain, then LLVM itself does already have either two or three internal IRs, and god only knows how modern linkers work in practice.
Re:Introducing MIR by Joky on Thursday April 28, 2016 @12:20AM (#11586542)
I don't think it is a bug against LLVM: there are basically two way of doing this: either you extend LLVM with more intrinsic or concept that carry your high-level semantics to the LLVM level (this is what people from Azul are doing [0]) or build an other intermediate representation like Swift and Rust. For the swift case, you can see the talk at last year LLVM Dev Meeting [1]. There are advantages and drawback to each approaches.

[0] : "LLVM for a managed language: what we've learned" [1] : "Swift's High-Level IR: A Case Study of Complementing LLVM IR with Language-Specific Optimization" Both have slides and video here: http://llvm.org/devmtg/2015-10/

Re:Introducing MIR by hacker_9 on Wednesday April 27, 2016 @12:55PM (#11582195)
It's not a bug, and the answer is provided in the link:

"Faster execution time. You may have noticed that in the new compiler pipeline, optimization appears twice. That’s no accident: previously, the compiler relied solely on LLVM to perform optimizations, but with MIR, we can do some Rust-specific optimizations before ever hitting LLVM – or, for that matter, before monomorphizing code. Rust’s rich type system should provide fertile ground for going beyond LLVM’s optimizations."

Re:Introducing MIR by kibwen on Wednesday April 27, 2016 @01:15PM (#11582376)
There's still an implicit question there, concerning why one would choose to develop a new IR rather than enhancing LLVM (the latter of which the Rust devs (and especially the Swift devs) have had years of experience doing). Though I'm not trying to suggest that Rust made the wrong decision or is suffering from NIH, because MIR is great, and there's no reason to suspect that shoving absolutely everything down into LLVM is necessarily a tractable solution. I'm just curious which Rust-specific and Swift-specific optimizations these IRs enable above and beyond LLVM IR's capabilities, and what that says about each source language in turn (especially if we regard LLVM IR as a proxy for C, being LLVM's original target).
Re:Introducing MIR by rayiner on Wednesday April 27, 2016 @01:50PM (#11582748)
It's easiest to do optimizations on an IR that has the appropriate level of granularity. If you're trying to optimize address calculations, it's easier to work with something like LLVM's getelementptr, which represents an address calculation as one IR node, than a C-level IR (where the address calculation would be implicit in an array or structure field access), or an ASM-level IR (where the address calculation might be broken up over several different instructions).

LLVM is pretty low-level. It's a bit lower-level than C and has a very simple type system. It has no idea about unique pointers versus references, has no concept of borrowing, etc. I bet you could encode the necessary information for performing say borrow-checking into LLVM IR, but working with that would not necessarily be pleasant.

A good example of this is ARC optimization in Swift, which gets rid of unnecessary reference counting operations. That optimization operates on SIL, which has special instructions for reference counting. You could represent those instructions as magic intrinsics in LLVM IR, but you have no way of imposing any structural restrictions on how those intrinsics are used. Moreover, any pass which operated on LLVM IR to optimize uses of those intrinsics, would have to make deep assumptions about the semantics of those operations. Those assumptions, being Swift-specific, would mean the pass could not be used by other languages, which removes a lot of the benefit of making it an LLVM pass in the first place.

Re:Introducing MIR by DannyBee on Wednesday April 27, 2016 @02:30PM (#11583198)
For starters, LLVM has a very simple type system. very simple. So pretty much any optimization that relies on type knowledge, unless it's a simple optimization (IE can be expressed as an attribute on lowered types, ...) needs are a higher level IR. Things are also legal in LLVM IR that are not legal in any of the languages it supports, for example, getelementptr can be used with negative indices, etc.

Some language rules and optimizations are easy to express in LLVM IR, but there are plenty that are not.

You could add metadata, but you'd probably have to extend how metadata works to support a bunch of things, and even then, the community would want metadata designs that multiple language frontends can use, not just yours.

Re:Introducing MIR by pklausler on Wednesday April 27, 2016 @02:40PM (#11583299)
> Things are also legal in LLVM IR that are not legal in any of the languages it supports, for example, getelementptr can be used with negative indices, etc.

Not sure what you're talking about here; what's wrong with negative indices in C?

Re:Introducing MIR by DannyBee on Wednesday April 27, 2016 @05:02PM (#11584526)
First, remember that getelementptr != array indices.

Second, remember that even in C, you can't actually dereference things outside of the bounds of an object, even if you can form addresses to it.

In any case, the point was more than something like

  struct foo C;

  char *foo = &C
  foo -= 7;
  char whee = *foo;
Is legal in llvm, but not in say, C++ (and in fact, in most languages it's not legal because it's not aligned properly)
Re:Introducing MIR by pklausler on Wednesday April 27, 2016 @05:36PM (#11584766)
"char" in C/C++ can't be misaligned.
Re:Introducing MIR by DannyBee on Wednesday April 27, 2016 @09:23PM (#11585978)
I didn't say it can, i said "in fact, in most languages" (IE not C/C++). In C/C++, it's illegal for other reasons.
Re:Introducing MIR by kibwen on Wednesday April 27, 2016 @02:53PM (#11583446)
I Am Not A Language Lawyer, but there's no way that negative indices aren't UB in C.
Re:Introducing MIR by pklausler on Wednesday April 27, 2016 @02:58PM (#11583485)

  int a[100];
  int *p = &a[50];
  a[0] = 666;
  printf("%d\n", p[-50]);
Remember that x[y] in C just means *((x)+(y)). You can offset pointers with positive and negative offsets so long as the resulting pointer remains within the bounds of an object.

(EDIT: formatting so HN doesn't misinterpret code point U+2A.)

Re:Introducing MIR by munificent on Wednesday April 27, 2016 @04:28PM (#11584241)
I actually use negative indices in real code[1].

If you implement a stack using an array and you track the top of stack by a pointer just past the last element, then you can index negatively into that pointer to access items on the stack:

    // Create an empty stack.
    int stack[100];
    int* top = &stack;

    // Push a couple of values.
    *top++ = 123;
    *top++ = 456;

    // Peek the values.
    printf("%d\n", top[-1]); // 456.
    printf("%d\n", top[-2]); // 123.
You could make the pointer arithmetic more explicit like this:

    printf("%d\n", *(top - 1)); // 456.
But I think that's needlessly verbose.

[1]: https://github.com/munificent/wren/blob/master/src/vm/wren_v...

Re:Introducing MIR by jeffdavis on Thursday April 28, 2016 @03:55AM (#11587136)
For something like that, I would use the explicit pointer arithmetic. The array syntax implies (to me) "I am doing the normal thing with this normal array".
Re:Introducing MIR by kibwen on Wednesday April 27, 2016 @04:22PM (#11584200)
I'm aware that index notation in C is just sugar for pointer arithmetic, but I'm under the impression that the interpretation of "within the bounds of an object" is less liberal than that demonstrated in your code example. In particular it's not clear to me that a pointer derived from an offset into an existing allocation does not constitute a new object, with its own bounds. Maybe I'm just spoiled by languages with proper slices...
Re:Introducing MIR by pklausler on Wednesday April 27, 2016 @05:19PM (#11584665)
Your impression unfortunately turns out to not be the case. You can move pointers forward and backward within an array using pointer +/- integer arithmetic or (equivalently) the prefix and postfix ++/-- operators, and it's well-defined so long as you don't back up over the beginning of the array or go more than one element past the end.

See section 6.5.6, paragraph 8, of the ISO C standard, if you want the legalese. But this is pretty basic C that dates back to the beginning of the language.

Re:Introducing MIR by Gankro on Wednesday April 27, 2016 @07:12PM (#11585372)
This working is entirely necessary for C++-style handle-iterators to work. Rust's slice iterators are implemented in the exact same fashion precisely because C/C++ does this a lot and LLVM is trained to "get" it.
Re:Introducing MIR by odbol on Thursday April 28, 2016 @10:34PM (#11593429)
Does Rust using LLVM mean you can write iOS apps in Rust?
Re:Introducing MIR by steveklabnik on Friday April 29, 2016 @09:24AM (#11595521)
Yes, though you don't have access to the GUI toolkit stuff, so it's most suitable for stuff like games.
Re:Introducing MIR by sklogic on Wednesday April 27, 2016 @01:32PM (#11582552)
There is nothing surprising in this fact. I always argued that even a very simple language needs not one, not two, but dozens of consequent IRs. Why? See the recently opensourced ChezScheme.
Re:Introducing MIR by Church- on Wednesday April 27, 2016 @08:40PM (#11585822)
Why, what's up with ChezScheme?
Re:Introducing MIR by sklogic on Thursday April 28, 2016 @02:53AM (#11586934)
It is a practical and fast compiler implemented on top of Nanopass. A very good example of why the more IRs - the better.
Re:Introducing MIR by mtgx on Wednesday April 27, 2016 @03:09PM (#11583580)
Will Mir create any of the problems Swift's bitcode creates?

https://medium.com/@FredericJacobs/why-i-m-not-enabling-bitc...

Re:Introducing MIR by pdpi on Wednesday April 27, 2016 @03:27PM (#11583713)
The LLVM bitcode problems are mostly caused by using the LLVM IR as a distribution format. As long as the rust MIR doesn't leak into the outside world, I don't see how it might turn into an issue
Re:Introducing MIR by pcwalton on Wednesday April 27, 2016 @03:17PM (#11583646)
Most of those problems are non-issues (e.g. backdoor injection--Apple always has the ability to do this) and the remaining issues have nothing to do with Rust.