Unit vs Generic type?

I'm really confused trying to figure out how to use generics, clearly I'm doing it wrong. This is example code illustrating the source of my error. The real code is far too long. I hope I have clearly laid out the example.

so I have:

enum testType<T>{
    item(externalType<T>)
}

struct test<T>{
 example: Option<testType<T>>,
}

impl<T> test<T>{
    let a = testType::item(f()) //f() is a function that returns an externalType<()>
    fn new()->test<T>{
        example: Some(a),
    }
}

The problem is that I am getting an error mismatched types, expected enum testType found enum testType<()>

Why is the unit type not included in the generic types? How do I work around this as both are viable types for me in the struct?

If f() yields an externalType<()>, then the only test<…> that you will be able to construct using it is test<()>(≠ test<T> for arbitrary caller-chosen Ts).

Hence:

- impl<T> test<T>  {
+ impl    test<()> {
      …
-     fn new() -> test<T>  {
+     fn new() -> test<()> {
2 Likes

As an additional nitpick: please don't start types with a lower case letter. It messes with the pattern recognition of others who read the code.

3 Likes

You lost me. My understanding was that T represented any type. The unit type is not included in that set?

f() yields externalType<()> if the test.new() method is used, yes. But if a test is created "manually" without the method, a test could have any an externalType with any T.

The T is a type parameter, which means that the caller gets to choose it, just like the caller gets to choose values for all of a function's parameters-- Your code must work for any T that the caller chooses.
As written, your new() function only works when T = (), so @Yandros' solution is to restrict the function definition to that case only.

An alternative would be to define new such that it doesn't need to generate a value of type T:

impl<T> Test<T> {
    fn new()->Test<T> {
        Test { example: None }
    }
}
5 Likes

The important bit here is:

Basically, what happens if somebody wrote test::<i32>::new()? The generic parameter expresses the fact that, as an implementor, you can work with any type the caller may give you. In order to support such a claim, your code needs to be compatible with all possible choices of T. Yes, that choice of T may be (), but it may also be any other type.

If, within your function's body, you are only able to construct instances of externalType<()> (through f()), then that means that you are not able to produce externalType<T> for any caller-chosen type T, such as externalType<i32>.

That's why Rust complained. You either need to be able to construct Option<testType<T>> for any arbitrary type T, such as with None, as @2e71828 suggested, or you need to express that you can only handle T = (), by removing the caller-chosen genericity, and replacing it with a fixed usage of (), as I've suggested.

You could even go the extra mile:

enum TestType /* no generics */ {
    Item(ExternalType<()>), // Start using `()` already
}

struct Test /* no generics */ {
    example: Option<TestType /* no generics */ >,
}

impl Test {
    fn new() -> Self {
        let a = TestType::Item(f());
        Self {
            example: Some(a),
        }
    }
}

(In the event the return type of f() cannot be named, then this solution won't work on its own, and will require a bit of extra effort. That being said, you explicitly talk about the unit type, so I don't think this is your case. If it were, then feel free to ask about it, there are other threads in this forum where have talked in length about constructing types with impl Trait / unnameable types inside them.)

2 Likes

So if I'm understanding you correctly the compiler is complaining that the T !=T in the sense that I have defined that any type can be put in, but created a function that is only capable of producing a specific type? I think I understand that.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.