(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)
EDIT: great community, shitty website.
Such as?
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...
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.
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.
http://research.microsoft.com/en-us/um/people/moskal/pdf/msc...
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.
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.
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...