Private type in public interface


#1

In my current project I implemented a type IRef which is defined as follows:

pub struct IRef<N>(pub u32, PhantomData<N>);

impl<N> IRef<N> {
    pub fn id(&self) -> u32 {
        let IRef(id, _) = *self;
        id
    }

    // some details omitted
}

This is used as a helper type for several other reference-like types that are based off an internal u32 and that all work identical.
To define such a reference type the following code is required:

struct DummyVar;
pub type VarRef = IRef<DummyVar>;

I do this “trick” with the DummyVar struct to differentiate on the type-level between different kinds of reference types based on the IRef.
And it is useful to me that DummyVar is a private struct since it has no other use than to be a different type than other type-params for this generic IRef class.

However …

types/var_ref.rs:7:24: 7:32 warning: private type in public interface, #[warn(private_in_public)] on by default
src/microsat/types/var_ref.rs:7 pub type VarRef = IRef<DummyVar>;
                                                       ^~~~~~~~
types/var_ref.rs:7:24: 7:32 warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!

My Questions

  • But why? I can understand that this is generally not a wanted behaviour, but in my use case it makes perfectly sense to not declare DummyVar as a public type.
  • Are there decent work arounds for this problem?
  • And as always: Do I something terribly wrong here?

Edit:

I also seem to have problems exporting this type alias “VarRef” for usage in other modules. Can anybody explain why? The Compiler errors the following on instanciating a VarRef:

    pub fn var(&self) -> VarRef { // VarRef as ret type works
        let Lit(val) = *self;
        VarRef(val & 0x7FFF_FFFF) // does not work - error: VarRef undeclared
        (val & 0x7FFF_FFFF).into() // works
    }

Thanks!


#2

What you perhaps want to try instead of your type def is something like an associated type, though I cannot tell you off the top of my head, whether those have to be public either.

Your second problem seems to be related to the fact that IRefs signature is (u32, PhantomData<N>) and you use pass (u32).


#3

Thank you for your replay. I cannot imagine how associated types may help me. The only thing I actually want to have are multiple types that behave absolutely the same but are different types. In C++ I would easily create this with a single-parameter template class and multiple typedefs to a different instance of that template. Simiöar to what I have just tried in Rust.
Hope it is clear now! :wink:


#4

Rust’s type parameters are rather different from C++ templates. I’m not 100% clear what you want here, but it sounds more like you want a trait than a type with a type parameter.

You do something like this:

pub trait IRef {
    fn id(&self) -> u32;
}

And then impl that for all your types. I’m rather confused though, because the id seems to be stored in some struct that doesnt actually have an association with the types themselves, other than a PhantomData. I need to know more info about what you’re trying to accomplish.

The issue with the alias is in your edit is that type aliases don’t create new type constructors, you need to use IRef(..., PhantomData) to construct your VarRef.


#5

I think I got it working now in the following way:

pub struct IRef<N>{ // no longer a tuple-struct
    id   : u32,
    mark : PhantomData<N>
}

impl<N> IRef<N> {
    pub fn new(val: u32) -> Self { // now has a simple constructor
        IRef{ id: val, mark: PhantomData }
    }

    pub fn id(&self) -> u32 {
        self.id
    }
}

And with this I can define new reference-like types that are different to each other on a type system level that are based on a u32 internally with as much code as this:

pub struct DummyVar; // would be better if this could be private
pub type VarRef = IRef<DummyVar>;

And another reference-like data type that is completely different (from a type system perspective) than the one defined above:

pub struct DummyClause; // would be better if this could be private
pub type ClauseRef = IRef<DummyClause>;

The question is still though (as in the beginning) why the DummyVar and DummyClause helper structs have to be public. In this specific use-case it would be much better if they could be private without warnings or future deprecations!

Regards