0

I want to do this...

let myInt = E.i(420)
let myString = E.s("Crook")

...with this...

enum E {
  case i(Int?)
  case s(String?)

  func i() -> Int? { 
    // How do I implement?
  }

  func s() -> String? {
    // How do I implement?
  }
}

...so I can do this...

let theInt = myInt.i()
let theString = myDouble.s()

...or even better, do this...

let betterInt = myInt.i
let betterString = myString.s

...or if I want to be in heaven...

let i = myInt // based on associated value return typed value as Int or nil
let i: Int = myInt // convert it automatically and return Int or nil

let s = myString // based on associated value return typed value as String or nil
let s: String = myString // convert it automatically and return String or nil
jscs
  • 63,694
  • 13
  • 151
  • 195
griftopia
  • 135
  • 1
  • 3
  • 10
  • 1
    Have you looked at the Swift documentation? – Gary Makin Feb 04 '18 at 22:19
  • 1
    Why do you need to declare your associated values as optionals? Just declare them as non optional types. – Leo Dabus Feb 05 '18 at 00:01
  • Gary Makin - Yes my friend. I have looked at the swift documentation. I don't treat stackoverflow like twitter. Josh Caswell - In hindsight, perhaps my example wasn't clear. I'm looking for my enum to represent ONNE data type value so I will have initializers and not instantiate the normal way by passing the associate value along with the case type. Leo Dabus - Int? is different type than Int. I want to say it is Int, but value may or may not be present. – griftopia Feb 05 '18 at 01:42
  • Please don’t add answers to your own question if the answer merely updates your question. You may not treat SO like Twitter, but I’m afraid you‘re not using it like it is intended either. – CodingMeSwiftly Feb 05 '18 at 04:09
  • Cabus - My question is still open. There is no place to provide formatted code unless I say "Answer". Maybe I'm mistaken – griftopia Feb 05 '18 at 14:29

4 Answers4

1

You could do something like this:

enum E {
  case i(Int?)
  case s(String?)

  var i: Int? {
    switch self {
    case .i(let value): return value
    case .s(_): return nil
    }
  }

  var s: String? {
    switch self {
    case .i(_): return nil
    case .s(let value): return value
    }
  }
}

Sadly, your heavenly solution is not quite feasible. You would have to overload the = operator and afaik this is forbidden in Swift (Apple Documentation).

CodingMeSwiftly
  • 3,231
  • 21
  • 33
1

I'm not sure how what you're trying to do is different from a type cast.

if you have :

let myInt = 420
let myString = "Crook"

then

let i = myInt as? Int // makes i an Int? which would be nil if myInt didn't 
                      // actually contain an integer
                      // note that a non-optional Int would not accept a nil
                      // so heaven cannot work as you would expect

let s = mySting as? String // makes s a String? ...

Variables that you would have declared as E(...) simply need to be declared as Any.

If you want a specific subset of types, you could define a protocol for them and use it instead of Any.

for example:

protocol E 
{}
extension Int:E {}
extension String:E {}

let myVariable:E = 3

let i = myVariable as? Int

You could also extend your protocol for syntactic candy:

extension E
{
   var value:Int? { return self as? Int }
}

let i:Int? = myVariable.value
Alain T.
  • 40,517
  • 4
  • 31
  • 51
-1

Thanks to Cabus !!! I changed it slightly to avoid messy switch on the case

Not sure this will work with Generics. I didn't try because I wanted to restrict the type and didn't see a way to restrict to explicitly to types I need.

Also it's not perfect because I have to explicitly inform compiler when I'm using Int32 and Double. And specifying a "typed" nil is clunky. However I can live with that.

public enum D {
    case Int (Int32?)
    case Double (Double?)
    case String (String?)

    public init(_ i: Int32?) {
        self = .Int(i)
    }

    public init(_ d: Double?) {
        self = .Double(d)
    }

    public init(_ s: String?) {
        self = .String(s)
    }

    var int: Int32? {
        if case D.Int(let int) = self {  return int }
        return nil
    }
    var double: Double? {
        if case D.Double(let double) = self {  return double }
        return nil
    }
    var string: String? {
        if case D.String(let string) = self {  return string  }
        return nil
    }
}

Test code...

let myInt = D(Int32(2))
let myString = D("Two")
let myDouble = D(Double(2.0))
let myIntOptional = D.Int(nil) // when wanting to use "typed" nil

print("myInt = \(myInt.int)")
print("myString = \(myString.string)")
print("myDouble = \(myDouble.double)")
print("myIntOptional = \(myIntOptional.int)")

Appreciate any improvement suggestions.

griftopia
  • 135
  • 1
  • 3
  • 10
-1

So here's my solution using Generics.

public enum E<T> {
    case Value (T)

    public init (_ t: T) {
        self = .Value(t)
    }

    var value: T {
        switch self {
        case .Value(let t): return t
        }
    }
}

Test code...

let myInt = E<Int32>(2)
let myString = E<String>("Two")
let myDouble = E<Double>(2)
let myDate = E<Date>(Date())
let myIntOptional = E<Int32?>(nil)
let myIntOptionalWithValue = E<Int32?>(4444)

print("myInt = \(myInt.value)")
print("myString = \(myString.value)")
print("myDouble = \(myDouble.value)")
print("myDate= \(myDate.value)")
print("myIntOptional = \(myIntOptional.value)")
print("myIntOptionalWithValue = \(myIntOptionalWithValue.value)")

Test results...

myInt = 2
myString = Two
myDouble = 2.0
myDate= 2018-02-05 02:52:51 +0000
myIntOptional = nil
myIntOptionalWithValue = Optional(4444)

IMHO, it is now less messy and more readable and does what I need.

griftopia
  • 135
  • 1
  • 3
  • 10