Why Do We Need to Explicitly Cast the Optional to Any

Why do we need to explicitly cast the optional to Any?

Every type can be implicitly promoted to an optional of that type. This means that when you cast T? to Any it is very hard to know whether it was originally T or originally T? (or even T?? or worse). Most confusing is that Any can be promoted to Any? and that Any? is of type Any, so telling the difference between Any, Any?, Any??, and Any??? (etc.) is very tricky, and sometimes impossible.

Any is a very tricky type in Swift and should almost never be used. Except for explicitly tricking the compiler (in some very fancy and fragile type-eraser), I don't know of any case where it really makes sense to have Any as a variable type, and definitely not in the form of [Any]. If you're created an [Any], you've gone down a bad path that isn't going to go well.

There are a very few cases where Any as a function parameter type makes sense (print() being the most famous), but they are extremely rare in app-level code. If you find yourself needing Any, you've probably done something wrong, and the compiler is going to fuss at you about it and often make you write extra as code to make sure you really mean the messy things you're saying.

Just to give some concrete versions of this, optionality tends to be lost when you enter Any. So consider this situation:

let number: Int = 3
let optionalNumber: Int? = 3
let nilNumber: Int? = nil

let anyNumber = number as Any
let anyOptional = optionalNumber as Any
let anyNil = nilNumber as Any

if anyNumber is Int { print("number is Int")} // yes
if anyOptional is Int { print("optional number is Int")} // yes
if anyNil is Int { print("nil is Int")} // no

if anyNil is Int? { print("nil is Int?")}
// -> Error: Cannot downcast from 'Any' to a more optional type 'Int?'

Rats.

We can't get our optional back the same way we put it in. We can promote it of course:

if (anyNil as Any?) is Int? { print("nil is Int?") }  // yes

But we can promote anything that way, since everything is implicitly an optional of itself:

if (anyNumber as Any?) is Int? { print("number is Int?")}  // also yes

So, um. Rats. We don't really know if it was originally optional or not. It's mess, and the compiler is warning you that it's going to be a mess if you go very far down this road. T->Any is a bit of magic. T->T? is also a bit of magic. Combine the two magics, and you had better know exactly what you're doing.

Swift: why do I need optionals anyways?

Optionals

If you know for sure that a variable should never be nil, you can force unwrap an optional using ! or declare as implicitly unwrapped using String!. This will cause a crash when it is nil, exactly like you want.

But, with some variables it is reasonable for them to be nil. For example, a User model whose age variable isn't set because the user didn't supply it.

Explicitly marking them as optional and unwrapping them using if let forces you to think about nullability. In the end, this creates more robust code.

I don't think it leads to shorted code. Where in Objective-C you would use if var != nil you use if let var = var in Swift. Sending a message to nil in Obj-C is a noop, you can get the same behavior in Swift using var?.method(). It's kinda the same in the end.

Casting (as)

A big reason you need casts right now in Swift is because some Objective-C methods return id, which was no problem in Obj-C but causes trouble in Swift. I expect this to diminish as Swift becomes more popular and frameworks are adapted.

Updated code

I quickly looked over your code and it looks you don't need half those casts. This is from the top of my head:

if let viewController = self.storyboard?.instantiateViewControllerWithIdentifier("Home") as? UIViewController {
if let window = UIApplication.sharedApplication().delegate?.window {
window.rootViewController = viewController

UIView.transitionWithView(window, duration: 0.2, options: .TransitionCrossDissolve, animations: {
window.rootViewController = viewController
}, completion: nil);
}
}

Why is a cast operator to std::optional ignored?

In case Barry's excellent answer still isn't clear, here's my version, hope it helps.

The biggest question is why isn't the user-defined conversion to optional<int> preferred in direct initialization:

    std::optional<int> my_opt(my_foo);

After all, there is a constructor optional<int>(optional<int>&&) and a user-defined conversion of my_foo to optional<int>.

The reason is the template<typename U> optional(U&&) constructor template, which is supposed to activate when T (int) is constructible from U and U is neither std::in_place_t nor optional<T>, and direct-initialize T from it. And so it does, stamping out optional(foo&).

The final generated optional<int> looks something like:

class optional<int> {
. . .
int value_;
. . .
optional(optional&& rhs);
optional(foo& rhs) : value_(rhs) {}
. . .

optional(optional&&) requires a user-defined conversion whereas optional(foo&) is an exact match for my_foo. So it wins, and direct-initializes int from my_foo. Only at this point is operator int() selected as a better match to initialize an int. The result thus becomes 2.

2) In case of my_opt = static_cast<std::optional<int>>(my_foo), although it sounds like "initialize my_opt as-if it was std::optional<int>", it actually means "create a temporary std::optional<int> from my_foo and move-assign from that" as described in [expr.static.cast]/4:

If T is a reference type, the effect is the same as performing the
declaration and initialization
T t(e); for some invented temporary
variable t ([dcl.init]) and then using the temporary variable as the
result of the conversion. Otherwise, the result object is
direct-initialized from e.

So it becomes:

    my_opt = std::optional<int>(my_foo);

And we're back to the previous situation; my_opt is subsequently initialized from a temporary optional, already holding a 2.

The issue of overloading on forwarding references is well-known. Scott Myers in his book Effective Modern C++ in Chapter 26 talks extensively about why it is a bad idea to overload on "universal references". Such templates will tirelessly stamp out whatever the type you throw at them, which will overshadow everything and anything that is not an exact match. So I'm surprised the committee chose this route.


As to the reason why it is like this, in the proposal N3793 and in the standard until Nov 15, 2016 it was indeed

  optional(const T& v);
optional(T&& v);

But then as part of LWG defect 2451 it got changed to

  template <class U = T> optional(U&& v);

With the following rationale:

Code such as the following is currently ill-formed (thanks to STL for
the compelling example):

optional<string> opt_str = "meow";

This is because it would require two user-defined conversions (from
const char* to string, and from string to optional<string>) where the
language permits only one. This is likely to be a surprise and an
inconvenience for users.

optional<T> should be implicitly convertible from any U that is
implicitly convertible to T. This can be implemented as a non-explicit
constructor template optional(U&&), which is enabled via SFINAE only
if is_convertible_v<U, T> and is_constructible_v<T, U>, plus any
additional conditions needed to avoid ambiguity with other
constructors...

In the end I think it's OK that T is ranked higher than optional<T>, after all it's a rather unusual choice between something that may have a value and the value.

Performance-wise it is also beneficial to initialize from T rather than from another optional<T>. An optional is typically implemented as:

template<typename T>
struct optional {
union
{
char dummy;
T value;
};
bool has_value;
};

So initializing it from optional<T>& would look something like

optional<T>::optional(const optional<T>& rhs) {
has_value = rhs.has_value;
if (has_value) {
value = rhs.value;
}
}

Whereas initializing from T& would require less steps:

optional<T>::optional(const T& t) {
value = t;
has_value = true;
}

How to upcast object contained in Java 8 Optional?

I would write a method like this:

@SuppressWarnings("unchecked")  // Safe. See below.
static <T> Optional<T> copyOf(Optional<? extends T> opt) {
return (Optional<T>) opt;
}

(If you don't like the name copyOf, see my comment about Guava's ImmutableList below)

This is very efficient in terms of runtime speed: the cast gets elided at compile time:

static <T> java.util.Optional<T> copyOf(java.util.Optional<? extends T>);
Code:
0: aload_0 # Read the parameter.
1: areturn # Return the parameter.

so the only cost is that of a method call; this is easily done away with by the JIT.

You can then invoke like:

Optional<A> a = copyOf(func2());

This is safe because Optional has the following property: it is guaranteed not to have any state changes caused by setter methods taking parameters dependent upon the type variable T. Phew. Quite a mouthful. I'll make it more concrete.

Because Optional

  1. has no setter methods (of any kind, but more generally none that take parameters of type T, SomeGenericType<T> etc)
  2. is final (so you can't subclass it to add a setter to violate the previous point)

there is nothing you can do to the value held by the Optional<T> (or lack thereof) that will make it not an instance of T (or lack thereof).

And because every instance of T is also an instance of its superclasses, there is nothing unsafe about:

SuperclassOfT s = optionalOfT.get();

As such, this method is type safe (it will fail if you've invoked it on a non-present optional; but that's not a type error).

You will find similar code in Guava's ImmutableList.copyOf (the inspiration for calling it "copyOf" above, even though it's not really a copy). There, there are setter methods (like add), but those methods immediately throw UnsupportedOperationExceptions, and thus do not affect the list's state.


Note that whilst immutable types have the necessary properties described above to make such a cast safe, the type does not necessarily need to be immutable to perform the cast safely.

For example, you could have an ErasableOptional<T> type, which has an erase() method on it which, when called, converted a "present" value into an "absent" value (i.e. get() no longer succeeds). It would be safe to cast such an instance to an ErasableOptional<SupertypeOfT> because the value is either a T or absent; you can't make it not an instance of SupertypeOfT or absent.

How does this work - Java 8 Optional.of and Optional.ofNullable

Take a look at the declaration of the method,

public static <T> Optional<T> ofNullable(T value)

So this takes T and returns Optional<T> So in your case it takes Integer and returns an Optional<Integer>

So when you do this,

Optional.ofNullable(new Integer(10)).orElse(10);

The orElse call will unwrap the optional and returns the value in it if it is not empty. Otherwise it merely returns the given value.

Update

As per the following comments you can simplify it further while leaving the job to the Autoboxing.

Optional.ofNullable(10).orElse(10);

Uses for Optional

The main design goal of Optional is to provide a means for a function returning a value to indicate the absence of a return value. See this discussion. This allows the caller to continue a chain of fluent method calls.

This most closely matches use case #1 in the OP's question. Although, absence of a value is a more precise formulation than null since something like IntStream.findFirst could never return null.


For use case #2, passing an optional argument to a method, this could be made to work, but it's rather clumsy. Suppose you have a method that takes a string followed by an optional second string. Accepting an Optional as the second arg would result in code like this:

foo("bar", Optional.of("baz"));
foo("bar", Optional.empty());

Even accepting null is nicer:

foo("bar", "baz");
foo("bar", null);

Probably the best is to have an overloaded method that accepts a single string argument and provides a default for the second:

foo("bar", "baz");
foo("bar");

This does have limitations, but it's much nicer than either of the above.

Use cases #3 and #4, having an Optional in a class field or in a data structure, is considered a misuse of the API. First, it goes against the main design goal of Optional as stated at the top. Second, it doesn't add any value.

There are three ways to deal with the absence of a value in an Optional: to provide a substitute value, to call a function to provide a substitute value, or to throw an exception. If you're storing into a field, you'd do this at initialization or assignment time. If you're adding values into a list, as the OP mentioned, you have the additional choice of simply not adding the value, thereby "flattening" out absent values.

I'm sure somebody could come up with some contrived cases where they really want to store an Optional in a field or a collection, but in general, it is best to avoid doing this.

How to fix the warning of type casting in 'if let' statement in Xcode 8.3?

Try to cast to an optional Date:

if let date = nsdate as Date?

You're trying to optional cast of optional NSDate to NON optional Date. As long as NSDate is bridged from obj-c to Date, so this cast always success, so no optional cast required here, just basic cast as is enough. Then you need to cast optional value, so the resulting value has to be optional too, therefore Date? is appropriate here.



Related Topics



Leave a reply



Submit