Compare enums with associated values in Swift - ios

For enums with associated values, Swift doesn't provide the equality operator. So I implemented one to be able to compare two enums:
enum ExampleEnum{
case Case1
case Case2(Int)
case Case3(String)
...
}
func ==(lhs: ExampleEnum, rhs: ExampleEnum) -> Bool {
switch(lhs, rhs){
case (.Case1, .Case1): return true
case let (.Case2(l), .Case2(r)): return l == r
case let (.Case3(l), .Case3(r)): return l == r
...
default: return false
}
}
My problem is that I have a lot of such enums with a lot of cases so I need to write a lot of this comparison code (for every enum, for every case).
As you can see, this code always follows the same scheme, so there seems to be a more abstract way to implement the comparison behavior. Is there a way to solve this problem? For example with generics?

As of Swift 4.2 just add Equatable protocol conformance.
It will be implemented automatically.
enum ExampleEquatableEnum: Equatable {
case case1
case case2(Int)
case case3(String)
}
print("ExampleEquatableEnum.case2(2) == ExampleEquatableEnum.case2(2) is \(ExampleEquatableEnum.case2(2) == ExampleEquatableEnum.case2(2))")
print("ExampleEquatableEnum.case2(1) == ExampleEquatableEnum.case2(2) is \(ExampleEquatableEnum.case2(1) == ExampleEquatableEnum.case2(2))")
I.e. default comparison takes associated values in account.

Currently there is no way of achieving this without writing out all the cases, we can hope that it'll be possible in a later version.
If you really have a lot of cases and you don't want to write them all out, you can write a small function that generates the code automatically for you (I've been doing this just recently for something that wasn't possible to refactor)

Related

Using Enums’ associated values to link cases from first Enum to 2nd, then call an associated function value from the CaseIterable second

I’m building a weather app that will provide access to multiple weather providers from which I get slightly-to-very different data sets returned. I want to make the system that handles the setting up of the data to be as generic as possible to accelerate the addition of new providers.
Firstly, I have an enum RValueUnits that consists of all possible units that values can be returned in:
enum RValueTypes { /// returned value
case cm
case celsius
case decimal
case mm
case percentage
case inch
/// etc
}
Some providers, for example, may return precipitation amount in .mm, others in .cm.
What I want is for each provider to have an enum of their own listing all the properties that they return including the return type. For example:
enum DarkSkyProps: CaseIterable {
static var allCases: [DarkSkyProps] {
return [
.apparentTemperature(unit: .celsius, setter: setApparentTemperature)
]}
case apparentTemperature(unit: RValueType, setter: () throws -> Void)
}
The setter function associated with each case handles the property’s data set up. For example, it would compare the return value type from the provider with the user’s preference, and if it’s different, it will change it before setting it as the value of the associated property, for example apparentTemperature in the above case.
static func setApparentTemperature() throws {
/// processing logic goes here
}
I have one issue and one question:
Firstly, I wanted DarkSkyProps to be CaseIterable so the setup is automatic. However, I have no idea how to call the iterated case’s associated setter function:
for property in DarkSkyProps.allCases {
/// want to call property.setter()
}
Secondly, ideally I also want there to be enum ForecastSource such as:
enum ForecastSource {
case DarkSky
case Foreca
}
And for each to be associated with a Props enum (i.e. ForecastSource.DarkSky is linked to DarkSkyProps), like:
case DarkSky(props: DarkSkyProps.AllCases)
So that I then need to only write something like, for example:
var source: ForecastSource = .DarkSky
for property in source.props {
/// want to call property.setter()
}
Is there a way?
Finally, considering what I’m aiming for, is there an actually entirely different approach that is more suitable?
Many thanks!

How do I check type of an object in a switch/case?

I see in examples this code:
if (obj is User) { // do something }
I want to check the type of the object in a switch/case flow, and found a property .runtimeType of the object:
switch (obj.runtimeType) {
case User:
print(obj);
break;
}
Is this a correct way to check the type of the object?
There is no support in the Dart switch statement for switching by type.
You should use a sequence of if tests instead:
if (obj is User) {
print(obj);
} else if (obj is ...) ...
I really, really recommend that you never use runtimeType for anything.
It can be used to reflect, using dart:mirrors, on the type of an object (but you can also just use reflect(object) to reflect on the object itself). Apart from that, using runtimeType almost always causes otherwise avoidable problems.
The only thing you can do with the Type object returned by runtimeType is to check it for equality. If you do that (like in the switch above), then you don't correctly handle subtypes. If you ever have a subtype of User in your system, like if User is an interface and the implementation class is different, or if you mock a User for testing, or any number of other causes, then the instance will not have User as runtimeType, and the code won't recognize it.
Or maybe it will, because runtimeType can be overridden by the user, and any class can choose to return User. Testing against runtimeType isn't a guarantee that the class is actually the one you check for.
When you compare for type, you should always use is because it correctly handles subclasses.
Subtype substitutability is one of the core ideas of object oriented programming, so you could say that if you use runtimeType, you are probably not doing an optimal OO design.
(There are cases where code uses other.runtimeType == MyClass in operator== to avoid being equal to a subclass instance to avoid the "ColorPoint" problem - but it means that it's impossible to make a subclass or interface implementation (which includes mocks) of that type and have it pass equality checks. That's a very subtle restriction that I would avoid in shared library code. What you do in your own application, that nobody else will depend on, is at least only your problem :smile:).
switch string works.
switchType(Object object) {
switch (MirrorSystem.getName(new Symbol(object.runtimeType.toString()))) {
case "Animal":
print('animal basic');
break;
case 'Cat':
print('Mouse for cat');
break;
}
}
switch (obj.runtimeType.toString()) {
case 'User':
print(obj);
break;
}
You can create a condition beforehand. Here is an example, as I bumped into this too:
String grade;
if(grade is String) {
grade = grade;
} else {
grade = null.toString();
}
switch(grade) {
case "A":
print("Good");
break;
case "B":
print("Nice");
break;
case "null":
print("Type a string");
break;
default:
print("failed");
break;
}
This way you can check if a value is present or it is an empty string. As mentioned above the easy part is to use a simple If - Else, but otherwise use this.

Xcode 8 :function types cannot have argument label breaking my build

It seems that for some reason Swift have chosen to make coding in it less readable by forcing users to remove completion handler parameter labels. I have read the Swift discussion and still think it's a mistake. At least they could have made it optional.
When building using Xcode 8 - is there a way to force the compiler to use Swift 2.3 so I don't get these errors anymore?
I have updated the option to use legacy Swift (under build settings)
but I still seem to get this error:
Function types cannot have argument label 'isloggedIn'; use '_'
instead
How can I keep my labels in my completion handlers?
The Swift designers decided to prohibit argument labels for function types.
The reasoning is explained here: https://github.com/apple/swift-evolution/blob/master/proposals/0111-remove-arg-label-type-significance.md
This is a frustrating and questionable choice, as prohibiting argument labels makes it much easier to incorrectly invoke closures, which seems more important than simplifying the language's type system.
Usability > ideology.
A workaround to consider. You can't do:
func doStuff(completion: (foo: Int, bar: String) -> Void) {
...
completion(foo: 0, bar: "")
}
... but you can do:
func doStuff(completion: ((foo: Int, bar: String)) -> Void) {
...
completion((foo: 0, bar: ""))
}
i.e. have a single unnamed argument to your closure which is a tuple, in this case (foo: Int, bar: String).
It's ugly in its own way, but at least you retain the argument labels.
Based on the information above - it appears that the only way to really fix this and ensure that its performant is to raise a proposal to
Make argument labels optional with a view to :
improving the speed of development ( without argument labels it requires us to scroll up to the top of the method each time we put in the completion handler.
Reduce Errors : ( I have already had several errors caused due to incorrect completion handler entries especially with those that expect boolean values)
Make code more readable across team members. Not everyone has only one team member and thus being able to easily pick up other peoples code is a must have.
Lastly good programming practice means that the solution should look as much like the actual item being developed. completionhandler: (newvalues, nil) looks less like the item being managed than completionhandler(results: newValue, error:nil)
I would love for people reading this to share their feedback/ comments
on this below before I submit it so I can show there are others that
support this.
Edit:
I have submitted the pitch here :
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20161010/028083.html
which appears to have been agreed. It looks like its going to happen, however the discussion is whether this is submitted as a Swift 4 improvement ( highly probable)
You have to use _ to make your parameters unnamed, and that is unfortunate. Instead of tacking _ on to each parameter and then blindly calling your function I would suggest making a wrapper object.
Since losing named parameters for function types introduces more risk that you will call the function with the wrong values, I would suggest wrapping the parameters in a struct and having that be the one and only parameter to your function.
This way the fields of you struct are named, and there is only one type of value to pass into your function. It is more cumbersome than if we were able to name the parameters of the function, but we can't. At least this way you'll be safer and you'll feel less dirty.
struct LineNoteCellState {
var lineNoteText: String?
var printOnInvoice = false
var printOnLabel = false
}
Here is an example of it being used:
cell.configure(editCallback: { (_ state: LineNoteCellState) in
self.lineNoteText = state.lineNoteText
self.printOnInvoice = state.printOnInvoice
self.printOnLabel = state.printOnLabel
})
Semi-workaround, note the _
completion: (_ success: Bool) -> Void

Swift `in` keyword meaning?

I am trying to implement some code from parse.com and I notice a keyword in after the void.
I am stumped what is this ? The second line you see the Void in
PFUser.logInWithUsernameInBackground("myname", password:"mypass") {
(user: PFUser?, error: NSError?) -> Void in
if user != nil {
// Do stuff after successful login.
} else {
// The login failed. Check error to see why.
}
}
The docs don't document this. I know the in keyword is used in for loops.
Anyone confirm?
In a named function, we declare the parameters and return type in the func declaration line.
func say(s:String)->() {
// body
}
In an anonymous function, there is no func declaration line - it's anonymous! So we do it with an in line at the start of the body instead.
{
(s:String)->() in
// body
}
(That is the full form of an anonymous function. But then Swift has a series of rules allowing the return type, the parameter types, and even the parameter names and the whole in line to be omitted under certain circumstances.)
Closure expression syntax has the following general form:
The question of what purpose in serves has been well-answered by other users here; in summary: in is a keyword defined in the Swift closure syntax as a separator between the function type and the function body in a closure:
{ /parameters and type/ in /function body/ }
But for those who might be wondering "but why specifically the keyword in?", here's a bit of history shared by Joe Groff, Senior Swift Compiler Engineer at Apple, on the Swift forums:
It's my fault, sorry. In the early days of Swift, we had a closure
syntax that was very similar to traditional Javascript:
func (arg: -> Type, arg: Type) -> Return { ... }
While this is nice and regular syntax, it is of course also very bulky
and awkward if you're trying to support expressive functional APIs,
such as map/filter on collections, or if you want libraries to be able
to provide closure-based APIs that feel like extensions of the
language.
Our earliest adopters at Apple complained about this, and mandated
that we support Ruby-style trailing closure syntax. This is tricky to
fit into a C-style syntax like Swift's, and we tried many different
iterations, including literally Ruby's {|args| } syntax, but many of
them suffered from ambiguities or simply distaste and revolt from our
early adopters. We wanted something that still looked like other parts
of the language, but which could be parsed unambiguously and could
span the breadth of use cases from a fully explicit function signature
to extremely compact.
We had already taken in as a keyword, we couldn't use -> like Java
does because it's already used to denote the return type, and we were
concerned that using => like C# would be too visually confusing. in
made xs.map { x in f(x) } look vaguely like for x in xs { f(x) },
and people hated it less than the alternatives.
*Formatting and emphasis mine. And thanks to Nikita Belov's post on the Swift forums for helping my own understanding.

Function with Enumeration Parameter (and Default value)

I wanted to create an extension method function called toCurrencyString that has one parameter that is actually an integer enumeration of type CurrencyFormatType. The enum and code would be:
enum CurrencyFormatType: Int {
/// Formats a standard currency string (localized) such as $45.35 or *45,00
case Standard = 1,
///Rounded currency format (rounds up last decimals and does not return any decimals in string)
Rounded,
///Will not include the thousands separator (, or .) in a string. Retains localized currency symbol.
WithoutThousandsSeparator
}
func toCurrencyString(currencyFormat: CurrencyFormatType = 1) -> String
{
..my switch code w/ default to the first option if nothing passed in
}
I'd like to do this so that I can call .toCurrencyString on NSDecimalNumbers without having to pass in the optional parameter (most of the time I won't need it), but on the few times I do, i'd like to use an enum to select other options.
It complains at me telling me that my enum doesn't conform to IntegerLiteralConvertible. I did a little reading on how this would work but couldn't figure out the code.
Could anyone shed some light on how to get this working?
thanks for your help!
My apologies, no sooner did I ask it than I figured it out. I should have waited a bit longer.
In hopes of helping others out, just a reminder about the 'Raw' aspect of enums:
Adding this to my function signature helped:
CurrencyFormatType.Raw = 1
Thanks!
alternately you could have done:
func toCurrencyString(currencyFormat: CurrencyFormatType = CurrencyFormatType.Standard) -> String
{
...

Resources