How a function can return two types?

Hey, I'm trying to return two different types in one function, in OOP normally i utilize polymorphism.
Example, a have a simple interface or an abstract class and an instance that implements that interface, so, I can have two types that implements that interface.

Pseudo Code

public interface base {
    public void something();
}

public class One implements base {
    public void something() {}
}

public class Two implements base {
    public void something() {}
}

public class Operation {
    public base test() {
        if (true) {
            return new One();
        } else {
            return new Two();
        }
    }
}

class Playground {
    public static void main(String[ ] args) {
        
        base base_one = new One();
        base base_two = new Two();
        
        Operation test = new Operation();
        
        base obj = test.test();
        
        obj.something();
        
    }
}

In Rust, the closest I got is trait object, but... I can't use a trait that contain a Self. The error is on function instance()

I know that the rust way is composition over inheritance, but how do you translate an old code base in OOP to Rust?, I have some projects that would like to make in Rust, but sometimes a I get stuck, is not simple to redefine an architecture. Anyway if you know a material that explain how to make x in y lang to rust. Sorry for the bad English.

You have to add where Self: Sized to trait methods that do not take self.

1 Like

It might be more helpful if you explain an actual scenario in which you've wanted to do something like this - in my experience, trying to translate OOP concepts directly into Rust makes things harder than they need to be.

4 Likes

thanks, now works but I can't use the TSociable::instance() right?

I don't have a concrete example now, but sometimes I need work with struct that I will know only in runtime, in this example I tried express this "problem".

Consider returning an enum. For one-off cases there's the either crate.

3 Likes

Trait objects are a valid solution to that (as is wrapping the types in an enum, as @kornel suggested) - you're only running into issues here because you're effectively trying to have a trait construct itself. That doesn't really work very well - you have to add the Sized bound as @mmstick suggested, but even then you can't use the TSociable::instance() way of calling the function. There's a good Stack Overflow thread on why this is the case here: rust - Why can a trait not construct itself? - Stack Overflow

The closest approximations to your original attempt that would work would be to either:

Which one would work best depends on the situation :slight_smile:

2 Likes

Thanks, the solution is more simple that I expect , I was really complicating the things.

1 Like