Evaluate if int matches a defined enum type - objective-c

I have an enum typedef containing several type definitions, eg:
ActionTypeSomething = 1,
ActionTypeSomethingElse = 2
And so on.
So a method I've written evaluates a passed int and then returns a value (for example, a string) accordingly.
(NSString *)evaluatAndReturnProperResult:(int)typeID
NSString *repsonseString;
switch (typeID)
case actionTypeSomething: {
responseString = #"an appropriate string for typeID"
}
...
return responseString;
So my switch evaluates each supported type and returns the correct string.
Now for my question:
I only want to return strings for supported types (i.e., in theory any integer could be passed). If there's no match, I return nil.
Obviously I can do this using exactly the method I already have. But could I (in theory) improve performance by evaluating the passed int to see if it matches any of my defined enum types BEFORE I send it through switch (the switch isn't massive, but I'd still rather just return nil at the beginning of the method if I know there's not going to be a match).
I'm sure this is easy, could someone suggest how to evaluate if my passed integer matches any define enum ActionType before I enter the switch? In this case I'm probably prematurely optimizing, but it's more of a general question about how to do achieve it (not if I should).

You can define 2 more enum values:
typedef enum {
ActionTypeMin = 1,
ActionTypeSomething = 1,
ActionTypeSomethingElse = 2,
ActionTypeMax = 2
} ActionType;
Then check:
typeID >= ActionTypeMin && typeID <= ActionTypeMax

The argument for your method shouldn't be an int, it should ideally be the enum you have defined. This gives you some compile time checking.
If this is not possible then your default case in the switch will handle it just fine - that's what they are designed for.

You are using a TypeDef that's to limit ActionEnum to a set of values, so you shouldn't be using int in your program except for up or downstream communication. Some would say not even then and that you should recive a string and map it to the enum and vice versa.
In terms of getting your strings the usual optimsatiin is
Have an array of strings from ActionType1 to ActionTypeN.
Use the enum as the index to look it up from the array.
The array will also give you the doings to map the string to the enum.
A simple if statement of the enum cast as an integer against teh bound of the array will let you deal gracefully with a bad value, though to me that should throw a big blaring exception.

Related

Function that can return something or nothing

Is it possible to define a function in Kotlin where you can either return something or return nothing? I thought maybe to use Any as the return type, but that still requires the function to return something, although perhaps there is a way to return a Unit when the return type is Any?
I also found "Nothing":
Nothing has no instances. You can use Nothing to represent "a value that never exists": for example, if a function has the return type of Nothing, it means that it never returns (always throws an exception).
Unfortunately that will throw an exception. That's too bad. I wonder why they throw an exception?
You can wrap the result in a sealed class
sealed class Result<out T> {
data class Success<out T>(val value: T): Result<T>()
object Failure: Result<Nothing>()
}
Then for calling it you can
fun <Type>calculateResult(...): Result<Type> {
//calculate and return some implementation
}
And then
val result = calculateResult(inputs)
when (result) {
is Success -> {
val value = success.value
}
is Failure -> {
//Do something like show an error the user you know your value is Nothing
}
}
You can just use a nullable return type.
Otherwise, to address whether you can return Unit, you can. Unit is just a Kotlin object so you can get the instance by name:
return Unit
However I wouldn't recommend it, there are plenty of better options.
In regards to Nothing, it is a special type that is used to represent a function never returning. So if I wanted to write a function that throws an exception, I could do so with the Nothing return type. Then the inference engine knows that nothing past my function call will get executed.
Well if you think about it, a function can't return something or nothing, because what's the result of calling it? Do you have a value, or nothing at all? If you assign the result to a variable, but there is no result, that variable has no value, so what is it? The function has to either be defined as always returning something or always returning nothing, so you always know if there's a return value and what its possible types are. Otherwise we're getting into philosophical territory!
In fact in Kotlin, functions always return something - if you don't specify a type, like a void function in Java, it will default to returning Unit. This is a special value that represents a function not returning a result, but it is still a result type that gets returned. It's not nothing, it's a a thing. Every function has to return a thing.
So if you want to define the thing you return as either "a value that represents a thing" or "a value that represents nothing", you need a type that is capable of expressing both those ideas. You have three basic approaches I think:
use a specific value to represent "no value", e.g. -1 for an Int, "NO_VALUE" for a String, that kind of thing
create a type that defines a "no value" version of itself, like the Result type in one of the answers, the Optional type in Java, etc
just use null because nullable versions of every type are built into Kotlin's type system, and the standard library is geared towards handling them. Check out these features built around working with nulls
Use the nullable types IMO - return a String? or whatever and if the result is non-null, do something with the value. If it is null, ignore it. Kotlin makes that pretty easy! If you get to the point where you need to roll a special type, you'll probably know why you need it over your good friend null

Kotlin "let{}" Doesn't Provide Smart Cast

Just learned Kotlin Nullable type and let{} function which replaces the if (xx != null) {} operation.
But one thing I am confused is that, we all know and I Think the Complier Should Know that when we use let{}, the variable/object who is calling this function is possiblly null, however the complier still requires me to add the safe call operator "?" after the variable name instead of providing Smart Cast like it does in if (xx != null) {}. Why?
My piece of code:
fun main() {
var number1: Int? = null
//val number2 = number1.let { it + 1 } ?: 10 //doesn't work, not quite "smart"
val number2 = number1?.let { it + 1 } ?: 10 //works, must have "?"
println(number1)
println(number2)
}
You've already got answers in the comments, but just to explain the ? thing...
Kotlin lets you make null-safe calls on nullable variables and properties, by adding ? before the call. You can chain this too, by doing
nullableObject?.someProperty?.someFunction()
which evaluates nullableObject, and if it's non-null it evaluates the next bit, otherwise the whole expression evaluates to null. If any part of the chain evaluates as null, the whole expression returns null.
So it has this short-circuiting effect, and you can use the elvis "if null" operator to create a default value if you can't evaluate the whole chain to a non-null result:
nullableObject?.nullableProperty?.someFunction() ?: defaultAction()
and once you introduce the null check in the chain, you have to add it for every call after that - it's basically propagating either the result of the previous bit, or the null it resolved to, so there's a null check at each step
The let block is just a scope function - you use it on a value, so you can run some code either using that value as a parameter or a receiver (a variable or this basically). It also has the side effect of creating a new temporary local variable holding that value, so if the original is a var it doesn't matter if that value changes, because your let code isn't referring to that variable anymore.
So it's useful for doing null checks one time, without worrying the underlying value could become null while you're doing stuff with it:
nullableVar?.let { it.definitelyIsNotNull() }
and the compiler will recognise that and smart cast it to a non-null type. An if (nullableVar != null) check can't guarantee that nullableVar won't be null by the time the next line is executed.

PHP 7.4 Typed property with floats / doubles

I apologise in advance if this is a lame question, Its my first.
I am building a small framework for a university project and I wanted to enforce types as much as possible, Great to see now that PHP 7.4 has strict types for properties,
But it is not being properly enforced even with declare strict_types.
Also on a side note, I know people say in PHP there is no difference between doubles and floats, but with typed properties, PHP does not recognise double as a data type.
See the simple code test below:
class FloatTest
{
private float $float;
private int $int;
function __construct()
{
}
public function setFloat(float $float):void
{
$this->float = $float;
}
public function getFloat()
{
return $this->float;
}
public function setInt(int $int):void
{
$this->int = $int;
}
public function getInt():int
{
return $this->int;
}
}
$ft = new FloatTest();
$ft->setFloat(8);//No error is thrown, converts to float but no decimals
$ft->getFloat();// Returns number 8 as float, but there is no enforcing of decimal point?
var_dump(is_float(8));//returns false
//Argument 1 passed to FloatTest::setInt() must be of the type int, float given
$ft->setInt(8.2);//Works as expected, great!
class DoubleTest
{
private double $double;
function __construct()
{
# code...
}
public function setDouble(double $double):void
{
$this->double = $double;
}
public function getDouble():double
{
return $this->double;
}
}
$dt = new DoubleTest();
//Argument 1 passed to DoubleTest::setDouble() must be an instance of double, int given:
$dt->setDouble(8);
$double = $dt->getDouble();
var_dump(is_double(8)); returns false
Based on this very simple test I have a few points which I find strange:
Why is PHP correctly enforcing the int type but not the float type?
Why is it that when I check with is_float() it returns false but the function accepts an integer?
Why is the integer type perfectly enforced but not the float?
Even though PHP has a valid double data type, why does it assume double is an instance?
double is definitely a primitive data type within PHP, as the is_double() function works perfectly,
See exception thrown above.
Basically what would be the best, cleanest work around to enforcing decimal numbers in PHP?
Why is PHP correctly enforcing the int type but not the float type?
Why is it that when I check with is_float() it returns false but the
function accepts an integer?
Because float range can contain integers without losing any data. In other words, float is like a superset of integers, so you can't say I only want floats i don't want integers even in strongly typed languages and even if your code is in strict_types mode.
Why is the integer type perfectly enforced but not the float?
PHP type declaration comes with coercive mode as default mode, so it's possible to change the declared type and no TypeError will be thrown only if it's possible for PHP to coerce values of the wrong type into the expected ones.
In your case you are passing 8(integer) to a method that expects a float, this is totally fine and PHP will not complain about it because coercing 8 to a float will not change anything/lose anything.
So what does strict_types do then ?
It will change the behavior of PHP from coercive to strict. That means PHP will not be tolerant when an involved operation could lead to data loss.
By taking your example when we set declare(strict_types=1) the following line will be a problem
$ft->setInt(8.2);//Works as expected, great!
Because we are trying to pass a float number to an int parameter which means a data loss (8.2 becomes 8 ) PHP will throw an exception
Fatal error: Uncaught TypeError: Argument 1 passed to
FloatTest::setInt() must be of the type int, float given
Even though PHP has a valid double data type, why does it assume
double is an instance? double is definitely a primitive data type
within PHP, as the is_double() function works perfectly
PHP has no double data type and is_double is just an alias of is_float()
Basically what would be the best, cleanest work around to enforcing
decimal numbers in PHP?
What you did is the best and cleanest work :)

Understanding Kotlin Type system, What is meant by `{Comparable<{ Double & Int }> & Number}` and how to work with that

So for example:
var a = true
val test = if (a) -1 else -3.2
I was expecting the Type of the test should be the most closest intersection of the type-hierarchy i.e. for Int and Double is Number.
But looking at the IDE, it seems to have a type of {Comparable<{ Double & Int }> & Number}.
And the weird thing is, I cannot specify it like that (since {} is reserved for creating lambdas), I can only set it to a type of Number.
And another wierd thing is that if I try some function from Comparable interface, it throws some error:
// Warning at value 2
// The integer literal does not conform to the expected type {Double & Int}
test.compareTo(2)
3.compareTo(-1.1) // possible
2.3.compareTo(100) // possible
// But why not this is possible, while it has inferred type of Comparable?
test.compareTo(2)
Could somebody help in understanding the concept here? And few questions:
How does that type work all together, i.e. how could one variable hold two types at once?
How could one specify that type explicitly?
How do you use functions from Comparable interface, when test has implementaion of it?
& here means an intersection type (which isn't supported in the Kotlin language itself, but the compiler uses them internally). You can see it mentioned in the (incomplete) specification.
Intersection types are special non-denotable types used to express the fact that a value belongs to all of several types at the same time.
"Non-denotable" means exactly that you can't specify that type. I am not sure but I think the extra { } in types are supposed to indicate exactly this.
In particular, Comparable<Double & Int> means you can only compare test to something which is both Double and Int, but there are no such values. The compiler could probably simplify it to Comparable<Nothing>.
the most closest intersection of the type-hierarchy i.e. for Int and Double is Number.
It's least upper bound, which is closer to union, not intersection. The specification actually calls it "union types", but that's not the normal usage of that term.
This least upper bound is not Number because it also takes least upper bound of the Comparable interfaces which works out to Comparable<Double & Int> because Comparable is contravariant:
lub(Int, Double) =
Number & lub(Comparable<Int>, Comparable<Double>) =
Number & Comparable<Int & Double>
This calculation is described under type decaying:
All union types are subject to type decaying, when they are converted to a specific intersection type, representable within Kotlin type system.
The answer to question 1 is that the compiler is doing its best to infer the type, inventing new constraints to describe it as it goes.
The answer to question 2 is that you cannot.
The answer to question 3 is that you cannot, because Int is not comparable to Double and vice versa. So none of the methods from Comparable are actually usable, but the value definitely implements Comparable against something. This is not useful for Comparable, but could be for another interface. For example, imagine:
interface ZeroAndComparable<T> {
fun compareTo(t: T): Int
fun zero(): T
}
val foo : ZeroAndComparable<Int> = someZeroAndComparableInt()
val bar : ZeroAndComparable<Double> = someZeroAndComparableDouble()
val foobar = if (a) foo else bar
val zero : Any = foobar.zero() // should work
foobar.compareTo(something) // cannot work

Unexpected result when comparing CharSequence.reversed() return value

Have noticed a strange behavior when comparing a result of CharSequence.reversed() method.
val s = "a"
val subSequence = s.subSequence(0, 1)
println("$subSequence == ${subSequence.reversed()}: ${subSequence == subSequence.reversed()}")
Results in:
a == a: false
Moreover subSequence.reversed() == subSequence.reversed() is also false.
Can someone explain this unexpected behavior?
CharSequence is actually an interface which classes like String and StringBuilder implements. The reason why the result of subSequence(0, 1) isn't equal to subSequence.reversed() is because of the actual types they return.
The subSequence(0, 1) call returns a String, while reversed() returns a StringBuilder. The equals-method will therefore return false because the types are different.
It will work as you would expect if you call toString() on the result of reversed():
val reversed = subSequence.reversed().toString()
println("$subSequence == $reversed: ${subSequence == reversed}") // Prints a == a: true
Converting back to a String fixes the issue because then the correct (expected) eqauals is applied:
val s = "a"
val subSequence = s.subSequence(0, 1)
println(subSequence.reversed() == subSequence.reversed()) //false
println(subSequence.reversed().toString() == subSequence.reversed().toString()) //true
Note that you are probably confused by what is shown by toString and how equality (equals) behaves.
What you see is the output of toString(). Any type can decide how it's object's string representation might look like by overriding that method. This however has no influence on how objects of that type are compared against each other. That is where equals (in some cases also compare) comes in.
Others wrote something about that the underlying type of the objects to compare isn't equal (one side StringBuilder and the other String). The actual problem however is that of the equals-method. It could be (usually it isn't done so for various reasons), that equals for a certain type supports equality of different types of objects (such a behaviour (would) should be mentioned in the interface at least). If nothing is specified one can assume that the default equality from Object.equals holds.
In this case however the CharSequence-javadoc already states the following about equality (emphasis mine):
This interface does not refine the general contracts of the equals and hashCode methods. The result of testing two objects that implement CharSequence for equality is therefore, in general, undefined. Each object may be implemented by a different class, and thereis no guarantee that each class will be capable of testing its instancesfor equality with those of the other. It is therefore inappropriate to usearbitrary CharSequence instances as elements in a set or as keys ina map.
So summarizing: forget that you got a String or StringBuilder from subSequence and reversed. The method contract specifies CharSequence and as such you must handle it as CharSequence. There is no guarantee that those functions will still return a String or StringBuilder in future.