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

Swift enums with associated values #2755

Closed
RuiAAPeres opened this issue Oct 27, 2015 · 9 comments
Closed

Swift enums with associated values #2755

RuiAAPeres opened this issue Oct 27, 2015 · 9 comments
Assignees
Labels

Comments

@RuiAAPeres
Copy link

I saw this question/answer, but how would you go with an enum with different types associated? A quick example:

enum FooBar {
 case Bar1(Foo1)
 case Bar2(Foo2)
 case Bar3(Foo3)
}

You would then have something like:

struct CollectionOfFoos {
   let foos : [FooBar]
}

How you would store this CollectionOfFoos. For the time being it's not a RLMObject subclass.

@tom-sparo
Copy link
Contributor

Just from my own experience with Realm but the developers will probably be able to answer this better.

This depends on what Foo1, Foo2, and Foo3 are. If they're all the same Realm object, my suggestion is probably a List<Type> that you then iterate through and convert to enums as the computed property (this might be slow, consider caching). If they're primitives, this is not currently implemented but there are some workarounds on the open issue. If they're not primitives and not all the same Realm objects... you probably want to make them Realm objects that all inherit from a custom base Realm object type so that you can store the base type for the List. If they're not Realm objects... make them Realm objects.

@RuiAAPeres
Copy link
Author

They are not all the same Realm object, otherwise it would be:

enum FooBar {
 case Bar1(Foo1)
 case Bar2(Foo1)
 case Bar3(Foo1)
}

I see that there are still some limitations. The problem I have with this:

make them Realm objects that all inherit from a custom base Realm object type

Is that they have nothing to do with each other.

@tom-sparo
Copy link
Contributor

Well in order for a List to hold objects they have to be of the same type. The only workaround I can think of without creating a base class is to have a List for each Foo type and then combining them all in a computed property to get the desired collection of Foo -- but again each unrelated Foo type would still have to be a Realm object

@mrackwitz
Copy link
Contributor

What @tom-sparo suggests here, would not work:

you probably want to make them Realm objects that all inherit from a custom base Realm object type so that you can store the base type for the List.

That's because polymorphism isn't supported yet. You can just store objects of a specific type.
You could follow though the second suggestion of having dedicated lists for each enumeration case.
Alternatively you can also introduce a wrapper type, which can bind all sorts of associated values and have your computed property on this type:

enum FooBar {
    case Bar1(Foo1)
    case Bar2(Foo2)
    case Bar3(Foo3)
}

// where Foo1, Foo2, Foo3 are either RealmSwift.Object subclasses or supported primitives.

// A wrapper object for the FooBar enum, able to store associated values of every single case.
class FooBarBox : Object {
    var fooBar: FooBar? {
        get {
            // Determine object type by the 
            if let bar1 = _bar1 {
                return .Bar1(bar1)
            } else if let bar2 = _bar2 {
                return .Bar2(bar2)
            } else if let bar3 = _bar3 {
                return .Bar3(bar3)
            } else {
                return nil
            }
        }
        didSet {
            switch newValue {
            case Bar1(let x):
                _bar1 = x
            case Bar2(let x):
                _bar2 = x
            case Bar3(let x):
                _bar3 = x
            }
        }
    }

    internal dynamic var _bar1: Foo1?
    internal dynamic var _bar2: Foo2?
    internal dynamic var _bar3: Foo3?
}

// Note: struct's accessors can't be dynamically overridden at runtime. It'd need to be a class inheriting from RealmSwift.Object to be able to persist it.
class CollectionOfFoos : Object {
    let foos = List<FooBarBox>()
}

@mrackwitz mrackwitz self-assigned this Oct 28, 2015
@tom-sparo
Copy link
Contributor

Wait really? Polymorphism isn't supported? In what way is it not supported? I've been using polymorphic classes as delegates for a bit and haven't been burned yet -- it seems to be working? Is this something I should expect to work only sometimes?

@mrackwitz
Copy link
Contributor

Inheritance is supported by Realm, but polymorphism not yet. It is supported by Swift though. See the detailed roundup here.

Inheritance in Realm at the moment gets you:

  • Class methods, instance methods and properties on parent classes are inherited in their child classes.
  • Methods and functions that take parent classes as arguments can operate on subclasses.

It does not get you:

  • Casting between polymorphic classes (subclass->subclass, subclass->parent, parent->subclass, etc.).
  • Querying on multiple classes simultaneously.
  • Multi-class containers (RLMArray/List and RLMResults/Results).

@tom-sparo
Copy link
Contributor

Thanks that's very helpful!

@mrackwitz
Copy link
Contributor

I will close this for now in favor of #921. Once that can be tackled, we an revisit this issue as well. Thanks for bringing this up though!

@RuiAAPeres
Copy link
Author

thanks @mrackwitz

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 17, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

3 participants