Overload by return type optionality?


(Rick M) #1

It seems I can write this:

extension String
{
  public func deleting(prefix inPrefix: String) -> String
  public func deleting(prefix inPrefix: String) -> String?
}

But I was hoping it would do the right thing:

let a = s.deleting(prefix: "foo")
if let b = s.deleting(prefix: "foo") { }

But it finds these ambiguous, and I'm not sure how to specify which I want.

I'm having trouble googling for an answer on this. Some answers around generics, but that doesn't apply in this case.

···

--
Rick Mann
rmann@latencyzero.com


(Joe Groff) #2

The first one is truly ambiguous since either overload works. If you specify the type of 'a', you should be able to choose one or the other:

let a: String = s.deleting(prefix: "foo")
let b: String? = s.deleting(prefix: "foo")

The `if let` should not be ambiguous, since only the Optional-returning overload is a valid candidate. Got time to file a bug?

-Joe

···

On Oct 13, 2016, at 2:36 PM, Rick Mann via swift-users <swift-users@swift.org> wrote:

It seems I can write this:

extension String
{
public func deleting(prefix inPrefix: String) -> String
public func deleting(prefix inPrefix: String) -> String?
}

But I was hoping it would do the right thing:

let a = s.deleting(prefix: "foo")
if let b = s.deleting(prefix: "foo") { }

But it finds these ambiguous, and I'm not sure how to specify which I want.


(Greg Parker) #3

You can specify which you want by explicitly naming the type:
    let a = s.deleting(prefix: "foo") as String
or
    let a : String = s.deleting(prefix: "foo")

…but presumably that doesn't give you the usability that you were hoping for.

···

On Oct 13, 2016, at 2:36 PM, Rick Mann via swift-users <swift-users@swift.org> wrote:

It seems I can write this:

extension String
{
public func deleting(prefix inPrefix: String) -> String
public func deleting(prefix inPrefix: String) -> String?
}

But I was hoping it would do the right thing:

let a = s.deleting(prefix: "foo")
if let b = s.deleting(prefix: "foo") { }

But it finds these ambiguous, and I'm not sure how to specify which I want.

--
Greg Parker gparker@apple.com <mailto:gparker@apple.com> Runtime Wrangler


#4

It works if you specify the types of the variables:

let a: String = …
if let b: String = …

Nevin

···

On Thu, Oct 13, 2016 at 5:36 PM, Rick Mann via swift-users < swift-users@swift.org> wrote:

It seems I can write this:

extension String
{
  public func deleting(prefix inPrefix: String) -> String
  public func deleting(prefix inPrefix: String) -> String?
}

But I was hoping it would do the right thing:

let a = s.deleting(prefix: "foo")
if let b = s.deleting(prefix: "foo") { }

But it finds these ambiguous, and I'm not sure how to specify which I want.

I'm having trouble googling for an answer on this. Some answers around
generics, but that doesn't apply in this case.

--
Rick Mann
rmann@latencyzero.com

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Rick M) #5

Here you go: https://bugs.swift.org/browse/SR-2942

···

On Oct 13, 2016, at 14:47 , Joe Groff <jgroff@apple.com> wrote:

On Oct 13, 2016, at 2:36 PM, Rick Mann via swift-users <swift-users@swift.org> wrote:

It seems I can write this:

extension String
{
public func deleting(prefix inPrefix: String) -> String
public func deleting(prefix inPrefix: String) -> String?
}

But I was hoping it would do the right thing:

let a = s.deleting(prefix: "foo")
if let b = s.deleting(prefix: "foo") { }

But it finds these ambiguous, and I'm not sure how to specify which I want.

The first one is truly ambiguous since either overload works. If you specify the type of 'a', you should be able to choose one or the other:

let a: String = s.deleting(prefix: "foo")
let b: String? = s.deleting(prefix: "foo")

The `if let` should not be ambiguous, since only the Optional-returning overload is a valid candidate. Got time to file a bug?

--
Rick Mann
rmann@latencyzero.com


(Rick M) #6

Eh, it's close, especially if Joe Groff is right that the if-let case shouldn't be ambiguous.

A better question would be to ask, is this a reasonable approach, to overload a method like this for this kind of behavior. There are two ways to think about stripping the prefix off a string: a string minus a non-existent prefix is just the string, or you want to know that the prefix didn't exist. This gives you both, but might make for subtly unexpected behavior.

Would it make sense to be able to specify priority for a set of overloaded methods to help resolve ambiguity?

···

On Oct 13, 2016, at 14:51 , Greg Parker <gparker@apple.com> wrote:

On Oct 13, 2016, at 2:36 PM, Rick Mann via swift-users <swift-users@swift.org> wrote:

It seems I can write this:

extension String
{
public func deleting(prefix inPrefix: String) -> String
public func deleting(prefix inPrefix: String) -> String?
}

But I was hoping it would do the right thing:

let a = s.deleting(prefix: "foo")
if let b = s.deleting(prefix: "foo") { }

But it finds these ambiguous, and I'm not sure how to specify which I want.

You can specify which you want by explicitly naming the type:
    let a = s.deleting(prefix: "foo") as String
or
    let a : String = s.deleting(prefix: "foo")

…but presumably that doesn't give you the usability that you were hoping for.

--
Rick Mann
rmann@latencyzero.com


(Luis Ferro) #7

It may also work if you create a "generic" extension that can only be applied to strings.

Then i'm guessing that you will not need to specify the type on the use.

LF

···

On 13/10/2016 22:44, Nevin Brackett-Rozinsky via swift-users wrote:

It works if you specify the types of the variables:

let a: String = …
if let b: String = …

Nevin

On Thu, Oct 13, 2016 at 5:36 PM, Rick Mann via swift-users > <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

    It seems I can write this:

    extension String
    {
      public func deleting(prefix inPrefix: String) -> String
      public func deleting(prefix inPrefix: String) -> String?
    }

    But I was hoping it would do the right thing:

    let a = s.deleting(prefix: "foo")
    if let b = s.deleting(prefix: "foo") { }

    But it finds these ambiguous, and I'm not sure how to specify
    which I want.

    I'm having trouble googling for an answer on this. Some answers
    around generics, but that doesn't apply in this case.

    --
    Rick Mann
    rmann@latencyzero.com <mailto:rmann@latencyzero.com>

    _______________________________________________
    swift-users mailing list
    swift-users@swift.org <mailto:swift-users@swift.org>
    https://lists.swift.org/mailman/listinfo/swift-users
    <https://lists.swift.org/mailman/listinfo/swift-users>

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Joe Groff) #8

Thanks!

-Joe

···

On Oct 13, 2016, at 3:27 PM, Rick Mann <rmann@latencyzero.com> wrote:

On Oct 13, 2016, at 14:47 , Joe Groff <jgroff@apple.com> wrote:

On Oct 13, 2016, at 2:36 PM, Rick Mann via swift-users <swift-users@swift.org> wrote:

It seems I can write this:

extension String
{
public func deleting(prefix inPrefix: String) -> String
public func deleting(prefix inPrefix: String) -> String?
}

But I was hoping it would do the right thing:

let a = s.deleting(prefix: "foo")
if let b = s.deleting(prefix: "foo") { }

But it finds these ambiguous, and I'm not sure how to specify which I want.

The first one is truly ambiguous since either overload works. If you specify the type of 'a', you should be able to choose one or the other:

let a: String = s.deleting(prefix: "foo")
let b: String? = s.deleting(prefix: "foo")

The `if let` should not be ambiguous, since only the Optional-returning overload is a valid candidate. Got time to file a bug?

Here you go: https://bugs.swift.org/browse/SR-2942


(Hooman Mehr) #9

This might be pretty useful in some situations, but I am not sure if the semantic complexity that it introduces is worth it.

Another example of how this could be useful:

I made a bare-bones rational number type <https://gist.github.com/hooman/6e08c48e1e06ee19e06e5b09f664f9be> for Swift a while ago. I would love to be able to overload “/“ operator to create fractions (rational numbers) instead of dividing two integers.

If I overloaded “/“ to return rational (Int / Int -> Rational), the result type of the operator would become ambiguous for every use of it with integer operands. It would be nice if I could prioritize my overload of “/“ over stdlib definition to resolve the ambiguity.

···

On Oct 13, 2016, at 3:31 PM, Rick Mann via swift-users <swift-users@swift.org> wrote:

Would it make sense to be able to specify priority for a set of overloaded methods to help resolve ambiguity?


(Mark Lacey) #10

Would it make sense to be able to specify priority for a set of overloaded methods to help resolve ambiguity?

I don’t think we want to head down that route, partially because using a contextual type as mentioned below removes the ambiguity.

This might be pretty useful in some situations, but I am not sure if the semantic complexity that it introduces is worth it.

Another example of how this could be useful:

I made a bare-bones rational number type <https://gist.github.com/hooman/6e08c48e1e06ee19e06e5b09f664f9be> for Swift a while ago. I would love to be able to overload “/“ operator to create fractions (rational numbers) instead of dividing two integers.

If I overloaded “/“ to return rational (Int / Int -> Rational), the result type of the operator would become ambiguous for every use of it with integer operands.

That isn’t the way the type checker works. If you use an explicit type to contextualize the expression, there is no ambiguity. For example this works without any ambiguity.

struct Rational {}
func / (lhs: Int, rhs: Int) -> Rational { return Rational() }
func + (lhs: Rational, rhs: Rational) -> Rational { return Rational() }

func use(r: Rational) {}

let x: Rational = (1 / 2) + (2 / 3) // Rational result type, no ambiguity
use(r: (1 / 2) + (2 / 3)) // Rational argument type, no ambiguity
let y = (1 / 2) as Rational // Calls func/(Int,Int)->Rational

Mark

···

On Oct 13, 2016, at 5:37 PM, Hooman Mehr via swift-users <swift-users@swift.org> wrote:

On Oct 13, 2016, at 3:31 PM, Rick Mann via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

It would be nice if I could prioritize my overload of “/“ over stdlib definition to resolve the ambiguity.

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Hooman Mehr) #11

I know, but a simple

let x = 2/3

becomes ambiguous which I don’t like.

···

On Oct 13, 2016, at 8:00 PM, Mark Lacey <mark.lacey@apple.com> wrote:

On Oct 13, 2016, at 5:37 PM, Hooman Mehr via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

On Oct 13, 2016, at 3:31 PM, Rick Mann via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

Would it make sense to be able to specify priority for a set of overloaded methods to help resolve ambiguity?

I don’t think we want to head down that route, partially because using a contextual type as mentioned below removes the ambiguity.

This might be pretty useful in some situations, but I am not sure if the semantic complexity that it introduces is worth it.

Another example of how this could be useful:

I made a bare-bones rational number type <https://gist.github.com/hooman/6e08c48e1e06ee19e06e5b09f664f9be> for Swift a while ago. I would love to be able to overload “/“ operator to create fractions (rational numbers) instead of dividing two integers.

If I overloaded “/“ to return rational (Int / Int -> Rational), the result type of the operator would become ambiguous for every use of it with integer operands.

That isn’t the way the type checker works. If you use an explicit type to contextualize the expression, there is no ambiguity. For example this works without any ambiguity.

struct Rational {}
func / (lhs: Int, rhs: Int) -> Rational { return Rational() }
func + (lhs: Rational, rhs: Rational) -> Rational { return Rational() }

func use(r: Rational) {}

let x: Rational = (1 / 2) + (2 / 3) // Rational result type, no ambiguity
use(r: (1 / 2) + (2 / 3)) // Rational argument type, no ambiguity
let y = (1 / 2) as Rational // Calls func/(Int,Int)->Rational

Mark

It would be nice if I could prioritize my overload of “/“ over stdlib definition to resolve the ambiguity.

_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users