Swift - Take Nil as Argument in Generic Function with Optional Argument - swift

I am trying to create a generic function that can take an optional argument.
Here's what I have so far:
func somethingGeneric<T>(input: T?) {
if (input != nil) {
print(input!);
}
}
somethingGeneric("Hello, World!") // Hello, World!
somethingGeneric(nil) // Errors!
It works with a String as shown, but not with nil.
Using it with nil gives the following two errors:
error: cannot invoke 'somethingGeneric' with an argument list of type '(_?)'
note: expected an argument list of type '(T?)'
What am I doing wrong and how should I correctly declare/use this function? Also, I want to keep the usage of the function as simple as possible (I don't want do something like nil as String?).

I guess the compiler can't figure out what T is just from nil.
The following works just fine though for example:
somethingGeneric(Optional<String>.None)

I believe you've overcomplicated the problem by requiring the ability to pass untyped nil (which doesn't really exist; even nil has a type). While the approach in your answer seems to work, it allows for the creation of ?? types due to Optional promotion. You often get lucky and that works, but I've seen it blow up in really frustrating ways and the wrong function is called. The problem is that String can be implicitly promoted to String? and String? can be implicitly promoted to String??. When ?? shows up implicitly, confusion almost always follows.
As MartinR points out, your approach is not very intuitive about which version gets called. UnsafePointer is also NilLiteralConvertible. So it's tricky to reason about which function will be called. "Tricky to reason about" makes it a likely source of confusing bugs.
The only time your problem exists is when you pass a literal nil. As #Valentin notes, if you pass a variable that happens to be nil, there is no issue; you don't need a special case. Why force the caller to pass an untyped nil? Just have the caller pass nothing.
I'm assuming that somethingGeneric does something actually interesting in the case that it is passed nil. If that's not the case; if the code you're showing is indicative of the real function (i.e. everything is wrapping in an if (input != nil) check), then this is a non-issue. Just don't call somethingGeneric(nil); it's a provable no-op. Just delete the line of code. But I'll assume there's some "other work."
func somethingGeneric<T>(input: T?) {
somethingGeneric() // Call the base form
if (input != nil) {
print(input!);
}
}
func somethingGeneric() {
// Things you do either way
}
somethingGeneric(input: "Hello, World!") // Hello, World!
somethingGeneric() // Nothing

Good question and answer. I have an Swift 4 update to contribute:
var str: String? = "Hello, playground"
var list: Array<String>? = ["Hello", "Coder256"]
func somethingGeneric<T>(_ input: T?) {
if (input != nil) {
print(input!);
}
}
func somethingGeneric(_ input: ExpressibleByNilLiteral?) {}
somethingGeneric("Hello, World!") // Hello, World!
somethingGeneric(nil) // *nothing printed*
somethingGeneric(nil as String?) // *nothing printed*
somethingGeneric(str) // Hello, playground
str = nil
somethingGeneric(str) // *nothing printed*
somethingGeneric(list) // ["Hello", "Coder256"]
list = nil
somethingGeneric(list) // *nothing printed*

I figured it out:
func somethingGeneric<T>(input: T?) {
if (input != nil) {
print(input!);
}
}
func somethingGeneric(input: NilLiteralConvertible?) {}
somethingGeneric("Hello, World!") // Hello, World!
somethingGeneric(nil) // *nothing printed*
somethingGeneric(nil as String?) // *nothing printed*

I think that you will never call somethingGeneric(nil) but mostly somethingGeneric(value) or somethingGeneric(function()) for which the compiler has enough info not to be stucked trying to guess the type:
func somethingGeneric<T>(input: T?) {
if let input = input {
print(input);
}
}
func neverString() -> String? {
return nil
}
let a: String? = nil
somethingGeneric("Hello, World!") // Hello, World!
somethingGeneric(a) // Nothing and no error
somethingGeneric(neverString()) // Nothing and no error
Also, I would use the if let syntax instead of if(value != nil).

Here is the solution I came up with that compiles on Swift 5, as many of the solutions here did not compile for me. It might be considered hacky as I use a stored variable to help things along. I was unable to come up with a Swift 5 version of the nil parameters that resolve to type T.
class MyClass {
func somethingGeneric<T>(input: T?) {
if let input = input {
print(input)
}
}
func somethingGeneric() {
somethingGeneric(Object.Nil)
}
}
final class Object {
static var Nil: Object? //this should never be set
}

Actually there is a way to do this, inspired by Alamofire's internal code.
You do not have to install Alamofire to use this solution.
Usage
Your problematic method definition
func someMethod<SomeGenericOptionalCodableType: Codable>(with someParam: SomeGenericOptionalCodableType? = nil) {
// your awesome code goes here
}
What works ✅
// invoke `someMethod` correctly
let someGoodParam1 = Alamofire.Empty.value
someMethod(with: someGoodParam1)
I think it is possible to use Alamofire.Empty.value as a default value in someMethod definition as a parameter.
What does not work ❌
// invoke `someMethod` incorrectly
let someBadParam1: Codable? = nil
let someBadParam2 = nil
someMethod(with: someBadParam1)
someMethod(with: someBadParam2)
Solution definition (source)
/// Type representing an empty value. Use `Empty.value` to get the static instance.
public struct Empty: Codable {
/// Static `Empty` instance used for all `Empty` responses.
public static let value = Empty()
}

Related

Can I constrain a generic parameter to *not* be optional?

Let's say I have this code:
func hello<T>(thing: T) -> String {
return "hello \(thing)"
}
Can I write a version of the hello function that won't compile if it's passed an optional?
let foo = "some"
let bar: String? = nil
print(helloNoOptional(foo)) // should compile
print(helloNoOptional(bar)) // should not compile
I'm thinking maybe it's doable with a protocol conformance or where clause on T but I can't think of how exactly that would work.
The reason I want to do this is because I'm dealing with a actual function in legacy codebase that has no sensible behavior if thing is nil. So I'd rather prevent hello from being called on an optional rather than deal with unwrapping thing inside of hello and trying to figure out a sensible error behavior.
Update:
A possible path...I realized that the Optional enum conforms to the NilLiteralConvertible protocol. So if I can find a way to constrain my generic to not conform to a type, I can exclude optionals de facto. But I don't know if it's possible to do something like
<T where !T: NilLiteralConvertible>
Best I can think of is overload and check at runtime:
func hello<T>(thing: T) -> String {
return "hello \(thing)"
}
fun hello<T>(thing: T?) -> String {
fatalError("No optionals allowed!")
}
hello("swift") // fine
hello(2) // fine
hello(Int("2")) // fatal error
But I don't know of a way of generating a compile-time error instead.
Edited
You can create a dummy protocol (NotOfOptionalType below) and extend all types you expect to use in your generic functions by this protocol. Finally use the dummy protocol as a type constraint for the parameter(s) in your generic functions; optionals does not meet this type constraint and you'll be given an error at compile time if they are sent as parameters for these functions.
// dummy protocol
protocol NotOfOptionalType {}
extension String : NotOfOptionalType {}
extension Int : NotOfOptionalType {}
extension Double : NotOfOptionalType {}
// ... extend to the types you will use
func hello<T: NotOfOptionalType > (thing: T) -> String {
return "hello \(thing)"
}
let foo = "some"
var bar: String? = nil
print(hello(foo)) // compiles
print(hello(bar)) // fails at compile time
bar = "something"
print(hello(bar)) // fails at compile time
print(hello(bar!)) // compiles
Building on #Airspeed Velocity's answer, I personally prefer to keep everything in one place, like so...
func hello<T>(_ thing: T) -> String {
if T.self is ExpressibleByNilLiteral.Type {
fatalError("Optional types not supported")
}
return "hello \(thing)"
}

Passing generic struct for unnamed default parameter results in garbage properties

I'm seeing some odd behaviour in a class I created a while ago, where it seems that a struct's properties are changing immediately after being passed (copied) to a method.
I've boiled it down to a simple test case that can be run in a playground:
struct StructToPass<T> {
let x: T
}
class MyClass<T> {
func createAndPassStructWithValue(value: T) {
let structToPass = StructToPass(x: value)
println("Before passing to method: \(structToPass.x)")
passStruct(structToPass)
}
func passStruct(_ theStruct: StructToPass<T>? = nil) {
println("Inside method: \(theStruct!.x)")
}
}
let myClass = MyClass<Int>()
myClass.createAndPassStructWithValue(42)
Looking at the relevant printed statements, it shows that the struct's x property has changed:
// Before passing to method: 42
// Inside method: 140734543799888
Creating the struct outside the class and calling passStruct(_:) directly causes the playground to crash, as does writing passStruct(_:) as a function:
// Causes playground to crash:
let aStruct = StructToPass(x: 42)
myClass.passStruct(aStruct)
// Also causes playground to crash:
func passStruct<T>(_ theStruct: StructToPass<T>? = nil) {}
passStruct(aStruct)
Changing the passStruct(_:) method/function to use the default external parameter name fixes the issue, as does introducing another parameter (before/after the default parameter):
// This works:
func passStruct<T>(theStruct: StructToPass<T>? = nil) {
println("Inside function: \(theStruct!.x)")
}
passStruct(theStruct: aStruct)
// This also works:
func passStruct<T>(_ theStruct: StructToPass<T>? = nil, someOtherParam: Int) {
println("Inside function: \(theStruct!.x)")
}
passStruct(aStruct, 42)
Is this a compiler bug? It seems the compiler doesn't like it when a generic function/method with a single argument with a default value doesn't use an external parameter name. It's a specific case, but I think it ought to work. If it shouldn't work, there ought to be a compiler warning.
110% compiler bug. I've even tried this out of Playground. It all happily compiles until you want to add a line which actually does something, like sending a passStruct. There's all kinds of things wrong with this. I even had this fail:
func passStruct<T>(_ theStruct: StructToPass<T>? = (nil as StructToPass<T>?)) {
println("Inside function: \(theStruct!.x)")
}
which I kinda thought might be the problem (even though it shouldn't be I've had that elsewhere).
Well found! Report it. They're clearly not finished with generics. In my experiments I found that generic class properties aren't allowed.
static let nilStruct: StructToPass<T>? = nil
does not compile, with one of the "not yet supported" error messages.

Why I can't use 'object== nil' in Swift?

I have simple method (hope the syntax is right)
func foo() -> WmGroupItemSample?{
var sample:WmGroupItemSample?
if(a > 0){ // some condition
sample = mGroupItemSampleList[0]
}
else{
// do nothing
}
return sample
}
As I understand foo method might return nil if statement a>0 doesn't occur. Therefore return type is: WmGroupItemSample?.
My doubts are in place where I call this method:
var sample:WmGroupItemSample? = foo()
if let temp = sample{
return sample.getStartDate()
}
else{
return -1
}
Is this proper way to validate if not nil? I use Beta 6
What difference if I'll call without ? or with ! like:
var sample:WmGroupItemSample = foo()
or:
var sample:WmGroupItemSample! = foo()
Why I can't validate sample like:
if sample == nil {
/* do one*/
}
else {
}
To compare value with a nil it has to be allowed to be a nil by ? mark. This means that the value can (possibly) be a nil. So by default:
var a : String
can not be a nil. To allow a string be a nil you have to do:
var a : String?
calling variable with ! is unwrapping an optional value
"Trying to use ! to access a non-existent optional value triggers a
runtime error. Always make sure that an optional contains a non-nil
value before using ! to force-unwrap its value." Excerpt From: Apple
Inc. "The Swift Programming Language."
iBooks. https://itun.es/pl/jEUH0.l
For more information I would suggest:
basics
more advanced
reading. Also that SO question with answer might be helpful.
You may have to implement either the Equatable or Comparable protocols.
implementing the Equatable protocol using a global function
func ==<T>(lhs:T, rhs: T?)-> Bool{
return lhs == nil
}
// in your class you can now extend the Equatable protocol in the class definition. ie
class ClassName: Equatable{
// properties and functions
}

Swift Optionals and Forced Unwrapping

I am having a hard time understanding the optionals and forced unwrapping in Swift language. I have read the book and chapters several times but I cannot understand it.
Is there a difference between the following two:
totalAmountTextField?.text.toInt()
totalAmountTextField!.text.toInt()
Also, when declaring the IBOutlets why do I always make it an optional field like this:
#IBOutlet var nameTextField :UITextField?
If I don't use the "?" at the end then it gives errors.
totalAmountTextField?.text.toInt() is equivalent to
func foo() -> Int? { // give you optional Int
if let field = totalAmountTextField {
return field.text.toInt()
} else {
return nil // return nil if totalAmountTextField is nil
}
}
foo()
it should be used if totalAmountTextField can be nil
totalAmountTextField!.text.toInt() is equivalent to
func foo() -> Int { // give you Int
if let field = totalAmountTextField {
return field.text.toInt()
} else {
crash() // crash if totalAmountTextField is nil
}
}
foo()
it should be used only if you know totalAmountTextField must not be nil
// It represents that totalAmountTextField may be nil and then stop the chain.
totalAmountTextField?.text.toInt()
// It assume that totalAmountTextField must have value, if not then caused a crash.
totalAmountTextField!.text.toInt()
You can take a look at the Swift Documentation about Optional Chaining. https://developer.apple.com/library/prerelease/mac/documentation/Swift/Conceptual/Swift_Programming_Language/OptionalChaining.html

How to check if a Generic type is nil in Swift

I'm trying to copy the all function from python to swift, starting off with checking for any nill items in a list, but I'm having a tough time checking optional items. For some reason I can send a optional string (string for example) and even though it says it's nil it still passes thru an if statement, which it doesn't outside of the function. Any advice about how to deal with this or another way of doing it? Thanks!
func `all`<T>(array: [T]) -> Bool {
for item in array {
if item as Any? {
println(item) // Says Nil >.<
}
var test: T? = item
if test {
println("Broken") // Prints broken :(
}
}
return true
}
var t: String?
all([t])
It's unclear to me exactly what you're trying to test, but maybe this will help.
The parameter to the function should be an Array of optionals [T?]
It may also be beneficial to directly compare elements to nil. The comparison could be abstracted to a closure much like the filter function uses.
func all<T>(array: [T?]) -> Bool {
for element in array {
if element==nil {
return false
}
}
return true
}
I know this is old, but it still being searched for. Just spent couple of hours looking for a solution and I think I have finally found one.
if (item as AnyObject) is NSNull {
//value is nil
}