Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Never patterns, exhaustive matching, and uninhabited types in Rust (smallcultfollowing.com)
161 points by fanf2 on Aug 18, 2018 | hide | past | favorite | 76 comments


Can someone explain why you'd want uninhabited types?

> if you have to define an error type for some computation, but this particular computation can never fail, you might use an uninhabited type.

I don't see the reason behind returning a Result<String, Err> if there is no error to return. Why not just return a String?


When you implement a generic trait that is designed to handle errors but your specific case is infallible then it is helpful to indicate that the error case can never occur. Marking that as uninhabited makes it easier for downstream consumers to just eliminate all code related to error handling for that concrete type.


An example I can think of is Java's StringReader class. It implements the Reader interface, so it has to bear the "throws IOException" signature... but it's impossible for it to produce an I/O error, since it's not actually doing any I/O, just reading from a String.

That's fine if you're using it via the Reader interface, but if you're working with StringReader directly it's a pain in the butt to deal with the non-existent exceptions. It sounds like never-patterns would help with that.


Please don't flame me if this is an ignorant question, but how is uninhabited different from Javascript's undefined? That's what I would use undefined for in JS (very loosely speaking).


You can actually set a variable to `undefined` in Javascript. You can't set a value to an uninhabited type─there is no value that represents the type.


I get it, so the concept is closer to declaring a variable and that's it, nothing further happens.

Thanks.


"undefined" is a type that has exactly one possible value. An uninhabited type has no possible value.


> Can someone explain why you'd want uninhabited types?

Uninhabited types are useful for expressing units.

I'm writing an app that makes heavy use of a Haskell library[1] that implements currency units and exchange rates using uninhabited types (type-level strings).

So, one dollar will have the type `Amount "USD"`, whereas one Euro will have the type `Amount "EUR"` (both will have a value of `1`).

An exchange rate from Euros to dollars will have the type `ExchangeRate "EUR" "USD"` (the first type parameter being 'source' and the second 'destination'), and its value will be `1.14` (the current exchange rate from EUR to USD).

A function for converting an amount in one currency into another currency unit will take two arguments: `Amount src` and `ExchangeRate src dst` and return an `Amount dst`.

Also, in general, it can be useful to:

1. Remove an argument from a function

2. Create an uninhabited type that, at the type level, represents the values of this argument

3. Tag the function's return type with this uninhabited "phantom" type

because now you no longer have to remember from which argument some return value was calculated/derived: it's right there in the value's type.

[1] https://www.stackage.org/haddock/lts-12.6/safe-money-0.6/Mon...


Consider the Ruby Gem, Fog[0]. It is designed to abstract different services away so that developers can just program against Fog and pick/choose different service providers as necessary. It's possible that for specific implementations of the fog-service boundary, an error cannot occur that definitely can occur in other implementations.

Uninhabitable types allow the implementer to tell the compiler "I cannot provide an error here", giving the compiler more information to work with when optimizing. For example, the compiler now knowing that the function call cannot return an error may make it so that the function does only return the string after optimization, and the compiler can also drop the error checking code in the caller because it's unreachable.

[0]: http://fog.io/


This kind of thing has been plenty annoying in C++ code. Things like switch, default, abort that used to catch RAM or CPU errors and provide useful information now get optimized away and execution continues in the face of impossible values.

Removing checks for "cannot possibly happen" cases isn't usually worth the tiny time savings.


> execution continues in the face of impossible values

I don't know about C++, but it may be doing something different from Rust here. In Rust, the ! type (which I pronounce "Never"), isn't just a case of "I, the programmer, don't think any value will exist here"; the compiler forces you to prove (just like every other type is a proof) that a value can't exist. The Never type can't be instantiated (it has no constructor), and functions that "return" Never must prove that they, er, never return; imagine a function whose body is just `loop {}` (or the stdlib function process::exit, which cannot return by dint of killing the callstack when the process dies).


I'm all for leaving asserts in release builds, but leaving in dead code based on uninhabited types isn't gonna help you catch RAM or CPU errors. You'll just continue into the error branch with an impossible value instead. It's the wrong layer for that.


This isn't an assert, it's not a runtime check; it's done at compile time. You need to prove to the compiler that your code can never reach this point; common ways of doing so are by calling exit or inserting an unconditional infinite loop. If your underlying computational platform is broken, this isn't going to save you, but I don't think there's much you can do at that point.


Yes, I know- that was my point. The comment I replied to was talking about CPU/RAM errors somehow bypassing that proof.


I think ones of the design books I read years ago talked about a piece of building infrastructure that “could not fail” so they incorporated it directly into the concrete pour.

Of course it failed, and it was a royal pain to get to the bits that failed because they were embedded in concrete that was probably holding the building up.

You build for robustness because you might be wrong, the new guy might not understand, or a silicon isotope might decay at just the wrong time and flip a bit. Circuits are analog. They just pretend very very hard to be binary. Weird shit can happen that shouldn’t be possible.


I think this is conflating two different concepts, only one of which concerns uninhabited types. If the programmer "knows" that a condition is impossible, but can't prove it to the Rust compiler, then they can the `unreachable!` macro to signal their intent to the compiler; in this case the compiler knows that it cannot trust the programmer (because it has no proof) and so generates code anyway that will handle the impossible condition (in this case, by panicking, which is the typical Rust reaction to a signal that the programmer's assumed invariants have been violated).

On the other hand, the use of an uninhabited type means that the programmer has to prove to the compiler that the type is uninhabited, in the same way that declaring a function as returning a String requires the programmer to prove that the function actually does return a String. If we have a function that returns a String, the compiler does not generate any code to handle the case where that function returns an integer instead; that just doesn't make sense, we've used the type system to prove that can't happen. Likewise, it wouldn't make any sense for the compiler to generate code to handle the case where a function returning an uninhabited type returns anything at all.


Static languages in general aren't good at catching impossible conditions.

If anything, you probably want something more like Erlang's supervision hierarchy where pattern-match failures (due to a cosmic ray, or anything else) kill the actor-process that was running, and then the actor's parent reinstanciates it and it tries again. Then you just need to draw fine-grained failure boundaries (i.e. what things end up in new actor-processes) to ensure that crashing out a process doesn't waste too much work unnecessarily.

Or the Mars-rover "six CPUs on separate NUMA nodes are each running a copy of the program, and quorum-consensus on the result of each function-call" strategy, but that's a bit expensive.


Perhaps you’re making use of a parametric type provided by a library, and you don’t have control over the structure except by filling in type parameters.


I mostly use them as return types for functions that are guaranteed to either loop forever or kill the process:

  noreturn mainloop(State* s)
    {
    for(; s->valid ;s->itick++) do_step(s);
    die(70,"invalid internal state");
    }


Types that represent producers of data often return a special result value at the end, of a type different from the values that are yielded. Say, a stream of integers that return a Boolean when it's exhausted.

By choosing an unhabited return type, you can express that the stream never stops producing values by itself.


A string is the worst thing to return because it’s huge. Most people return () instead which is zero sized.

However when returning ! the compiler can optimize the entire error handling away.


> A string is the worst thing to return because it’s huge. Most people return () instead which is zero sized.

I think what they're asking is "if you're returning a Result<String, Err>" but you're making the Err an unhinabitated type (so can't ever have an error) why not just return a String in the first place?


Because there are generic APIs that return results as part of the contract. A good example is FromStr.


A string is only like 16bytes (length + pointer to memory in heap) or more if it's a fat pointer.


I've used `enum Void { }` as a placeholder for opaque FFI managed types that I pass between APIs but never inspect myself. Like Windows handles (`*const Void`) or data structures that are queried using an API rather than directly.



Oh wow, I didn't know this. At one time at least it was recommended, which was why I did it.


Yeah, IIRC many years ago I added it in a document as a pattern for C APIs (I can't remember where though). Either other people were doing the same thing, or were influenced by that. Anyway, you should use `*const libc::void` these days! Sorry for the confusion.


Alright this is going to be a dumb question but...

Every time I start a new personal project I say 'oh neat I can use Rust!' N hours later (where N is a large number) I realize Go is about as fast, much easier and more readable syntax, and so I use Go if I want something that isn't Node. I'm a web developer so maybe Rust just isn't useful for that, but is Rust purely a systems level language for making super low level stuff? Forgive my ignorance, but what do people actually use it for where it outshines other languages?


I wrote a fair bit of go at my old job and I just finished a small internal rust utility at my current job. i liked go at first but then got completely fed up with the error handling, the module/folder nonsense, having to define the same function over and over for different primitive types when it came up, and nil. so I picked up rust. it's miles better. the syntax is not as bad you imagine - my utility is about 1000 lines and there are no lifetime parameters anywhere. the functional stuff is clean (closures, iterators, match). there are real enums (none of that iota nonsense) which as a "mature" developer have become integral to the design of any system for me. writing macros is easy (basically just like code gen in go). the borrow checker isn't that hard to satisfy - only one thing was a head scratcher and #rust-beginner helped me out there. cargo is great and so is RLS. there are a surprisingly large number of libraries given how young the language is (fewer than go for sure but enough that I didn't have to implement anything tedious myself). I mean it's just an all around pleasant experience and you're guaranteed to be writing performant (zero cost abstractions) safe code. how can you beat that? the only thing I miss from go are goroutines and the lightning fast compiler (but the rust compiler is plenty fast for how much it does). so I will probably use rust for everything other than what's fit for a python script from now on.


>you're guaranteed to be writing performant safe code

Let's not get overboard here


edited to clarify with zero cost abstraction


> and you're guaranteed to be writing performant safe code

That's very far from truth.


The problem here is the ambiguity of "safe", I think. Saying rust generates "guaranteed safe code" seems to imply that compiled rust can never do anything wrong, which isn't true.

Rust does make guarantees about certain kinds of safety, when not using unsafe {} blocks. You get memory safety and freedom from data-race issues. I don't know if any other languages offer that without incurring runtime costs.

Slow rust code is also possible, but your code can't really be slow because it is written in rust, in the same way that c doesn't get in the way of performance.


[flagged]


>If you have a meaningful contribution to conversation (e.g. you can enlighten us to instances where rust compiles down to inefficient or unsafe code) then make it.

This should be applied to your original unsubstantiated claim.

Rust has some features that improve safety. Writing code in Rust does not generate safe code.


I’m not sure what you mean by this: “Writing code in Rust does not generate safe code.”

I mean philosophically you could say there is no safe code, but then what’s the point of any language improvement.

Perhaps you mean that Rust has unsafe, which allows you to write unsafe code in Rust. But technically that term is reserved for the developer to make a claim that though the compiler can’t determine the safety of this code, the developer is claiming it is safe.

Then there is safe Rust, if you write safe Rust, the guarantees that the program output is safe are pretty high. Given that no software is devoid of bugs, it’s obviously not 100%.

So do you have a specific argument your making about why Rust is not safe? Or is it a general comment about software?

Edit: I suppose you could be pedantic in that rustc doesn’t generate code, but technically it does, mir and then llvmir. That code then gets compiled to platform specific binaries.


> mean philosophically you could say there is no safe code, but then what’s the point of any language improvement.

I have been writing safety critical code for living, so I think that saying that code "is safe" because it is written in some language is categorical error (not just error of degree) unless it is a language enables formally proofing correctness.

You can take fundamentally unsafe language like C. Restrict to subset of it MISRA C and use external static code analysis like Astree that that uses abstract interpretation to prove that there are no run time errors: no memory errors, no division of zero erros, no out-of-bounds array indexing, floating-point or integer overflows, loops always terminate, floating point rounding errors stay within specified limits etc. Something that Rust does not have.

Rust has some potential and there are some companies that attempt to provide tooling to make it possible to write safe Rust code, but it's not there yet.


That sounds exactly like an error of degree- Rust does have "no memory errors" proof tools already, built into the language.


>This should be applied to your original unsubstantiated claim.

my meaningful contribution is a first hand account of my experience with a variety of the aspects of using rust. one potentially imprecise sentence doesn't negate that contribution. you on the other hand with completely contentless sentence fragments are contributing absolutely nothing to the conversation.


"Guaranteed" is a very strong word. It's okay, though. Just admit that you overstated something, and then easily move on with your life. No big deal.

There is power and freedom in the act of letting go of former actions and moving forward, from time to time. If someone judges you for making a small mistake, maybe they are the one with the issue.

This is a lesson I'm still practicing as well, so this comment is just as much a reminder to myself.


I think Rust makes a lot of very hard things possible, at the expense of making some easy things more annoying.

That's a tradeoff that bothers a lot of people who hear the Rust hype, only to find that it's more annoying to write the things they want to write. But if you use Rust and it makes a very hard thing possible, this is an incredibly empowering experience and you'll become a passionate believer. This is a dynamic that leads to arguments on the internet.

I've never done any substantial low-level systems programming, but there are high-level situations where I think Rust was better than anything else.

In one case, I simply couldn't get decent performance for something out of any garbage collected language I tried -- and GC time was the actual bottleneck. Rewriting in C++ seemed very intimidating and likely to be error-prone. Doing the same thing in Rust gave me the same benefits with the confidence that I hadn't made any dumb memory errors.

The second benefit of Rust is that concurrency and parallelism is easy, in the sense that 1) for basic parallelism, you can use Rayon without even thinking about it, and 2) in more complex cases, you can share stuff across threads and be confident that you haven't introduced any weird, hard-to-debug race conditions.


Rust is a lot more palatable once you realize this unlisted tenet:

From what I’ve seen, Rust prioritizes improvements in this order:

Refactoring code can be one of the hardest but most beneficial things a dev can do for a code base, so let’s make that simpler.

Reading code is done 10x more than writing code, so let’s make that intuitive.

Writing code can be tedious, how do we help make things ergonomic.

What this means is that the mentality of a weekend project, or any code you will write once and forget about is the worst way to try out Rust.

I’d recommend trying Rust twice. Once to create the first draft that might be shitty. Then again in a week or month to refactor that same code.


The answers here will be subjective, but IMO Rust is useful for a much wider range of things than just 'super low level stuff'. I use it for anything from small command line tools to web backends if I have the option.

I appreciate it's approach to type safety and pattern matching, in fact, I find it pretty annoying to write code in a language that doesn't at least have sum types, pattern matching, and some kind of parametric/ad hoc polymorphism (Rust's traits feature).

Another nice thing about Rust is you can be pretty confident when writing multithreaded code. One of the slogans is 'fearless concurrency', and I think it lives up to that. I can write some little tool that does a bunch of things in parallel and know at compile time that I won't have any data races.

The tradeoff is that if you haven't written a lot of code in a lang with a similar type system, it can seem daunting.


Rust is comparable to C++ and exists in a similar space. Go is more comparable with Java (on a webserver), PHP, node, etc. Rust and Go exist in very different places although undoubtedly their Venn diagram overlaps at some weird point.

Horses for courses.


Comparable to Java 1.0 that is.


There are certainly different tasks for which different languages are suited, however for many tasks multiple languages are well-suited.

To paraphrase your question, you are essentially asking: "Why should I use language Y instead of X when X is fast enough for me, easier for me to read, and based on experience I like it better?" My immediate thought is that it sounds like language X is working quite well and aside from satisfying your personal curiosity there's no imperative to make that switch!


We use Rust extensively for much higher-level (platform & apps) level stuff, and it works very well for that, too. There is a learning curve, of course, and language preferences may legitimately vary -- but I don't think Rust is just "for making super low level stuff". (Oh, and we're hiring more full-time Rust developers).


Type safety and zero cost abstractions are the two main draws.


I feel that when it comes to web services, the choice between Rust and Go is one of style. I like Rust's style (type system etc), you like Go's. Either one is fine.


I work in AI research (the symbolic, tree exploration kind, not machine learning) and go solves most of my problems in this domain, because it is productive enough to let me try new algorithms all the time, yet fast enough to let me actually test those algorithms.

But sometimes it is not fast enough, and rust hits that sweet spot I need, offering both extreme speed (you can hardly go any faster in execution speed or memory management) and good enough productivity (something I can't achieve in C or C++ for various reasons, although they would be my second choice if I couldn't use rust for some reason).

So, I tend to use rust for not-super-low-level stuff (quite the opposite, actually), but this is somehow a last-recourse choice for me (I'd rather use go if I can, for productivity reasons).


I actually often wonder why so many web developers are drawn to Rust. Satisfying a borrow checker just doesn't seem like a worthwhile task when writing web apps. Are there things about Go that you feel are bad enough to warrant a switch to Rust?


For me, I have a fairly complex application sitting behind a http api. Rust allows me to keep the system requirements for an instance of the app low for better economy. (Memory use especially)

I actually like the ergonomics of it a lot and have learned to satisfy the borrow checker. I would use it over Java for almost anything.

The biggest downside to me is the long iteration times when making a change, compiling, and testing repeatedly.


Performance is not the only benefit. You also get freedom from data races, and (arguably) the borrow checker imposes structure that makes the program easier to read and reason about, because it's clearer who "owns" (and can mutate) what, and what is shared.

I've missed this property when writing Java and JS even before Rust was a thing, and Go has felt the same.


Exactly, the clear ownership in Rust allows you to skip the defensive copying that so often happens in Java. Of course you get this property in most languages that do not use garbage collection, but I few restrict mutable aliasing.


The type system is one of the main draws for me.


Typical that you'd be downvoted just for asking a question


Firstly stop comparing things in vacuum - you need to set expectations accordingly.

Go has google behind it, so regardless of anyone's opinion they can very well jam it down everybody's throat through sheer throwing money at the problem.

Go was build for fast web servers, not for what Rust is aiming for at all.

Rust also has this this obnoxious issue around it that has become a meme :

https://transitiontech.ca/random/RIIR

Rust CAN be a good choice for building a bluetooth driver or writing the logic for pacemaker (oh god no !).

But it has the steepest 90 degree hill to climb mainly because :

- untested in the wild.

- lack of libraries.

- API stability.

You should keep on using Go due to it being better tested, unless some large company throws a few billion dollars behind it, its going to take a lot of time for Rust to catch up on its own.

I bet even by 2025 rust wont get much traction unless some bigCo heavily invests in it, do not take my word for it - just look at purely open source projects like FreeBSD, Linux took nearly 20+ years to get any traction.


> - untested in the wild.

This is a 100% false statement. Here’s a list: https://www.rust-lang.org/en-US/friends.html

I’ve been really impressed with how much success people have had with cross platform deployments as well. At RustConf we just saw a talk about one company putting Rust on satellites, doesn’t get more “wild” than that.

> - lack of libraries.

There are some gaps. But new libraries are showing up every day. For middle of the road, non-exotic stuff, I would be surprised if a developer doesn’t have everything they need.

> - API stability.

In the library ecosystem this is a small problem. In the past 3 years I rarely am broken from library upgrades. For the language though, I have never in the same 3 years been broken by a language upgrade. Not to say there haven’t been bugs that the language needed to fix, but stable has never failed to compile my oldest Rust 1.0 code.

Please don’t spread information ignorant of facts.


Putting things on satellites might mean very different things. There is close to zero chance of anything critical being in Rust. One company I worked on has not even move from (a subset of) C90 for critical components. No C99, no C11, no C++03 and no Rust. It is likely that a company may have software in Rust, even running in a satellite module (though unlikely), but that is different than actual satellite systems being certified on Rust.

As for the rest of your argument: in many companies people is still moving to C11 or C++11. For many, software is considered for production only if it has been 5 years in the wild. A library appearing on cargo does not mean it is “available”.


Here’s the company and product for the sat reference: https://www.kubos.com/kubos/

> For many, software is considered for production only if it has been 5 years in the wild.

Time is irrelevant, it’s about usage and stability. Every rust crate I rely on has published download numbers, which give you an idea of number of people using it. In that set, they are all open source and published on GitHub or Gitlab, so I can look at the codebases easily.

You can wait, that’s fine. But you do end up missing out on helping shape a new environment that is growing at crazy rates over the last few years.


Sorry but that company/product looks like it is a Linux distro and framework tuned/supported for satellite hardware. That does not mean it controls the satellite nor that it is certified.

If you think “download numbers” (or open source, or being in GitHub) is a good metric for measuring reliability, it means you haven’t really worked in any such field.

It isn’t growing _at all_ in many fields, because it is simply way too new (no new software projects started on it), it isn’t certified (or even impossible to certify). That does not mean it is not better, so don’t take that as an attack. It is simply a suicide in risk-analysis to use a new language, new libraries and new compiler front-end in safety-critical projects; so it is a no-go. Similarly for C11, C++14, C++17 and many other languages, frameworks and libraries that you have to approve.


> If you think “download numbers” (or open source, or being in GitHub) is a good metric for measuring reliability, it means you haven’t really worked in any such field.

I never have worked in such a field, and you're comments about certification, etc, are definitely things I will accept as true. Getting any support of new technology in any space is hard, and of course takes time.

But, I will say that "download numbers" where there is obvious sustained usage of a project is a stand-in for understanding if something is seeing real-world usage. I don't claim that it show stability, only that if it's usage is high and the number of issues on the project are not growing under that strain then you can begin to get a picture of it's stability.

When you talk about formal proofs, certification, etc. Those are different mechanisms for validating that, but generally requires substantial amounts of money to be done.


The talk had a diagram, most components on it were in Rust, and the plan is to use more and more moving forward. Even critical stuff.


Happy to hear that, since I am not exactly in joy of using ancient languages.

However, from plans to actual usage takes years; specially for completely new projects using new languages, compilers, libraries, etc. in safety-critical stuff, that takes months just to validate.

Stating anything else is just either lying (marketing) or ignorance. Please do not do a disservice to your language by creating vacuous hype.


That was also a significant part of the talk. Like any industry, some shops are conservative, and some aren’t. Pointing out that some places are more liberal than others isn’t lying.


[flagged]


Personal attacks will get you banned here. Programming language flamewars are also definitely not welcome. Please don't post like this to HN.

https://news.ycombinator.com/newsguidelines.html


I don’t see any personal attack. Can you quote? I don’t even know nor care about the identity of people here.

As for flamewars, what are you even talking about? I have not said a single thing in favour of any language. Have you read the thread?


This is a personal attack: "It seems you don’t understand (or more likely you don’t want to understand)."

This is bullying: "Prove Rust is controlling critical systems _today_ ".

And this breaks the site guideline against calling names in arguments, as well as returning to personal attack: "Otherwise, please stop spreading bullshit".

Please review https://news.ycombinator.com/newsguidelines.html. Your comments need to be considerably more respectful if you want to keep posting here. There are plenty of ways to express your views about programming languages thoughtfully, including if you disagree with someone. It's not hard, if you take the spirit of this site to heart. We'd appreciate it if you'd do that.


Well, it seems you consider a “personal attack” any comment directed to another person, even if it is meaningful for the discussion and in-context. Your own guidelines ask for maintaining an identity (“On HN, users should have an identity that others can relate to.”); yet you don’t want any comments questioning anyone.

As for the rest: I don’t see how asking for proof can be considered “bullying”.

Please review the definition of bullying, because you are trivializing it and therefore hurting actual victims of bullying.

Thank you on behalf of them.

Finally, since it seems HN are in the business of deleting fair comments, I will leave the site and do my best warn others of what is happening here.

Good luck.


> (or more likely you don’t want to understand)

I'm not really gonna bother to reply when there's accusations like this.

I do understand everything you're saying. We're not in disagreement about the context. I (or more accurately, bluejekyll, we're talking about the same thing) did provide such a citation, you can take it or leave it.


By next year, Google may be the largest single employer of Rust programmers in the world. They might even already be, but the Fuscia team is aggressively hiring.

Facebook is too.

Amazon had a booth, I didn’t get a chance to talk to them about their current deployment personally.

Don’t underestimate China either, PingCap has huge deployments of their database, and while we may not hear about them often in the West, the numbers don’t lie.


This is a story worth developing further and reporting on


there are people right now writing production code in Nim, Crystal, Julia, and Joy (well maybe not Joy except for Jonathan blow himself). someone taking the plunge/risk on a new language is exactly how all three of those issues you allude to get resolved (as a dialogue between language users and language developers). I don't the Google go point? which big company is behind python? ruby? php? are those all also risky languages to build in?


I mean - I agree with a great deal with what you say...but Rust is backed by Mozilla which has written arguably the first or second most popular browser in current use. So, the bigCo argument seems misplaced. Also Google has a history of releasing languages that are often hugely unpopular (cough Dart cough) so I'm not sure that the money argument even holds even if it were true. Cool link though - Rust seems to be very popular among people who know of it, but don't use it.


( I use Firefox )

Mozilla is comparatively not a financial heavy weight like google, Microsoft.

Google has a history of doing a million things that fail, but that is exactly what i mean. They can spam the programming community with millions of things and something will eventually stick. Moz doesn't have that type of financial firepower so for them it's Rust or bust.


> This post describes the idea of a “never pattern” (written !) that matches against the ! type or any other “empty enum” type. It also describes an auto-never transformation that inserts such patterns into matches. As a result – in the desugared case, at least – we no longer use the absence of a match arm to designate matches against uninhabited types.

> Explicit ! patterns make it easier to define what data a match will access. They also give us a way to use lints to help bridge the needs of safe and unsafe code: we can encourage unsafe code to write explicit ! patterns where they might help document subtle points of the semantics, without imposing that burden on safe code.




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

Search: