Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SR-4273] Hashable & default function arg #46856

Closed
swift-ci opened this issue Mar 17, 2017 · 12 comments
Closed

[SR-4273] Hashable & default function arg #46856

swift-ci opened this issue Mar 17, 2017 · 12 comments
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself

Comments

@swift-ci
Copy link
Collaborator

Previous ID SR-4273
Radar None
Original Reporter mushroom (JIRA User)
Type Bug
Status Resolved
Resolution Won't Do
Environment

$ swift --version
Apple Swift version 3.0.2 (swiftlang-800.0.63 clang-800.0.42.1)
Target: x86_64-apple-macosx10.9

Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug
Assignee None
Priority Medium

md5: ba342c2e335167507d0b29222fc96dc1

Issue Description:

I use Hashable as a type constraint in my function, but it produces an error:

Default argument value of type 'Int' cannot be converted to type 'T'

func foo<T: Hashable>(_ a: T = 0) -> T {
    return a
}

Same with string:

func foo<T: Hashable>(_ a: T = "") -> T {
    return a
}

Same with AnyHashable:

func foo<T: Hashable>(_ a: T = AnyHashable(0)) -> T {
    return a
}

Thus in case of e.g. "" I expect:

foo() // returns ""
foo(1) // returns 1
foo("bar") // returns "bar"
@belkadan
Copy link
Contributor

I swear we've seen this before but I can't find it. Regardless, this wouldn't be valid because generic parameters can be controlled by context:

let x: Float = foo()

We'd have to have the notion of a default argument value that only kicks in under certain conditions, which gets complicated. You might as well just use overloads for that.

@swift-ci
Copy link
Collaborator Author

Comment by Andrew Pleshkov (JIRA)

Oh, I see, thanks.

Actually using such default argument was an attempt to fix this:

func find<T, Q: Hashable>(key: T, qualifier: Q? = nil) {
    // ...
}

find(key: "foo") // Generic parameter 'Q' could not be inferred

So I use an overload:

func find(key: String) {
    let q: AnyHashable? = nil
    find(key: key, qualifier: q)
}

And everything is fine.
Is there another way to help the compiler to infer 'Q'?

@belkadan
Copy link
Contributor

Not today, sorry. People have talked about adding "default types" to generic parameters but that would be a whole new language feature.

@swift-ci
Copy link
Collaborator Author

Comment by Andrew Pleshkov (JIRA)

But what totally solves my issue is using AnyHashable this way:

So I can rewrite find and remove the overload:

func find(key: String, qualifier: AnyHashable? = nil) {
    // ...
}

find(key: "foo") // compiles
find(key: "foo", qualifier: "kekeke") // compiles
find(key: "foo", qualifier: 123) // compiles

But it looks like a side-effect. Will such auto-boxing be broken in the future?

@belkadan
Copy link
Contributor

That means something different: now you've lost the type of the qualifier even when it's not nil. If that's not important to you this is a perfectly acceptable solution.

@swift-ci
Copy link
Collaborator Author

Comment by Andrew Pleshkov (JIRA)

In my case I just want the qualifier to be something hashable, but I can't write: find(key: String, qualifier: Hashable), so I tried to solve it via generics

@swift-ci
Copy link
Collaborator Author

Comment by Andrew Pleshkov (JIRA)

Thus can using of auto-boxing of one concrete Hashable to AnyHashable be a true swift-way in such case? This feature is undocumented (I couldn't find any info about it - only auto-boxing of Dictionary keys, but it's done via extension).

@belkadan
Copy link
Contributor

I thought it documented as part of the proposal that introduced AnyHashable, but maybe not. @jckarter?

@jckarter
Copy link
Member

It should also be in the language docs if it isn't already. Maybe we missed it—@jackhl might know where to look.

@jckarter
Copy link
Member

@jackhl
Copy link
Member

jackhl commented Mar 18, 2017

It's mentioned in Using Swift with Cocoa and Objective-C -> Interacting with Objective-C APIs -> Hashing:

The AnyHashable type is implicitly converted from any Hashable type, and you can use the as? and as! operators to cast from AnyHashable to a more specific type.

However it is not discussed at all in The Swift Programming Language book or the AnyHashable API reference. Since this behavior seems useful/important beyond Objective-C interop, I'll talk to the docs team about possibly adding more information in a more prominent location.

@swift-ci
Copy link
Collaborator Author

Comment by Andrew Pleshkov (JIRA)

Awesome, thanks a lot!

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself
Projects
None yet
Development

No branches or pull requests

4 participants