Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Created utility uninhabited type #6348

Closed
wants to merge 1 commit into from

Conversation

mstewartgallus
Copy link
Contributor

In this commit I added a useful utility type, named Void, that encapsulates the
doable but annoying job of creating an uninhabited type. As well, a function on
that type, named absurd, was created which is useful for ignoring the result of
matching on that type. No unit tests were created because it is not possible to
create an instance of this type to test the usage of.

This type is useful because it is like NonCopyable in that it can be used to
create a type with special characteristics without special bloat. For instance,
instead of typing pub struct PhantomType { priv contents : () } for each void
type one may want to use one can simply type pub struct PhantomType (Void);.
This type make such special cases much easier to write.

@brson
Copy link
Contributor

brson commented May 9, 2013

Related to #4724

@brson
Copy link
Contributor

brson commented May 9, 2013

Thanks! Can you give an example of how absurd would be used? Are there any synonyms that you also considered? The word absurd is sort of strange for a method name.

I think we probably also want to make libc::c_void a typedef for util::Void. Do you mind adding that commit?

In the future we might want to comb through the codebase to find places where c_void should be replaced with Void - it's not every occurrence but Rust code that just wants to use void pointers without other C interop should probably be using Void.

We may also want some conversion traits, e.g. VoidPtrable. It's a fairly common pattern in my bindings code to transmute between ~ and *c_void, but I'm not entirely sure what's needed here.

@mstewartgallus
Copy link
Contributor Author

@brson I was using absurd because it was the name of the function that another person used when doing a similar thing in Haskell. However, I was thinking of using uninhabitable instead of absurd to highlight the similarities to the function unreachable because they have similar purposes, (or maybe name the type Uninhabited.)

The use of absurd is similar to the use of uninhabitable. Consider a generic higher-order function "receive" that allows the user to optionable get a different type of value. In the following code absurd would simply be a less error prone alternative to unreachable.

do receive |value| {
      match value {
              Left(x) => x,
              Right(void) => void.absurd () // Extra feature of sometimes receiving alternative value is unused
       }
}

Using the type *Void would make sense except it's not possible to stop someone from dereferencing such a pointer to get a Void value. Maybe there is some kind of lifetime weirdness that could prevent someone from doing such a thing? Or alternatively one might implement something along the lines of a trait Void where the trait is somehow impossible to implement. Then one could use *Void all one wants without danger of dereferencing it to a value.

Personally I think that the best way of representing void pointers though is to think of them as using existential quantification. In other words, a void pointer is a pointer to a type T for some type T. This scheme can be implemented using traits (they quantify over the Self type.) I believe the following code works.

// The trivial trait implementable by everybody
pub trait Object { }
pub <T> Object for T { }

Then any pointer to a value should be easily castable to a pointer to an Object. Of course, one would have to use unsafe code to cast back. I don't remember how pointers to traits are represented. Is it possible to make a scheme like this be efficient, and compatible with C void pointers? Also, there is the issue of pointers to arrays of values. For example, the type &[Object] doesn't really make sense.

@brson
Copy link
Contributor

brson commented May 9, 2013

@sstewartgallus Besides copying are there additional reasons that you would want to forbid dereferencing *Void? c_void is uninstantiable and uncopyable by defining it as enum c_void { }, an enum without any variants. A similar definition seems appropriate here.

I like your idea about the Object trait. Object types (trait pointers) in Rust are fat pointers containing vtables so they do not have the same representation as a *c_void or ~-pointers, so I don't think it works as a substitute for *c_void. Something like you propose will probably be done eventually for the argument to fail!, which we have sometimes called ~Any.

In this commit I added a useful utility type, named Void, that encapsulates the
doable but annoying job of creating an uninhabited type. As well, a function on
that type, named absurd, was created which is useful for ignoring the result of
matching on that type. No unit tests were created because it is not possible to
create an instance of this type to test the usage of.

This type is useful because it is like NonCopyable in that it can be used to
create a type with special characteristics without special bloat. For instance,
instead of typing pub struct PhantomType { priv contents : () } for each void
type one may want to use one can simply type pub struct PhantomType (Void);.
This type make such special cases much easier to write.
@mstewartgallus
Copy link
Contributor Author

@brson Making the type pub enum Void { } is a much smarter idea. I did not know that syntax. In fact pub struct enum Foo { } is as good as pub struct Foo (Void);. I renamed the absurd method to uninhabited.

I guess using Void for pointers would make sense then.

I'm not sure that Object is really the same as an Any trait. As far as I understand an Any trait would have to have a few extra methods.

Here's what I think an Any trait might be (with the implementations automatically generated by the compiler.)

pub trait Any {
     fn size(&self) -> uint;
     fn type_name(&self) -> &'static str;
}

And maybe there'd be a number identifying the type. As well, I'd suggest such a trait would make sense to be called something like Introspectable.

bors added a commit that referenced this pull request May 12, 2013
In this commit I added a useful utility type, named Void, that encapsulates the
doable but annoying job of creating an uninhabited type. As well, a function on
that type, named absurd, was created which is useful for ignoring the result of
matching on that type. No unit tests were created because it is not possible to
create an instance of this type to test the usage of.

This type is useful because it is like NonCopyable in that it can be used to
create a type with special characteristics without special bloat. For instance,
instead of typing pub struct PhantomType { priv contents : () } for each void
type one may want to use one can simply type pub struct PhantomType (Void);.
This type make such special cases much easier to write.
@bors bors closed this May 13, 2013
flip1995 pushed a commit to flip1995/rust that referenced this pull request Dec 20, 2020
Resolves rust-lang#6348
Almost identical to print_stdout, this lint applies to the
`eprintln!` and `eprint!` macros rather than `println!` and
`print!`.
flip1995 pushed a commit to flip1995/rust that referenced this pull request Dec 20, 2020
Add lint print_stderr

Resolves rust-lang#6348
Almost identical to print_stdout, this lint applies to the `eprintln!` and `eprint!` macros rather than `println!` and `print!`.

changelog: Add new lint [`print_stderr`]. [`println_empty_string`] and [`print_with_newline`] now apply to `eprint!()` and `eprintln!()` respectively.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants