Name disambiguation of computed property/function with same type defined in extensions

IIRC, a member of the core team (Joe Groff, maybe?) indicated several months ago on the list that methods are internally namespaced to their module. Alas, I can’t find that message. It was a long time ago.

You can see this in the fact that two different files can see two different extension methods:

A.swift

    import ModuleA
    …
    "hello world".capitalized()

B.swift

    import ModuleB
    …
    "hello world".capitalized()

…even if they end up compiled into the same binary. And that makes sense: A.swift only expected to see ModuleA’s extension, and was presumably coded around that expectation. That ModuleB happened to end up mixed into the same binary shouldn’t change the behavior of A.swift

If my understand is correct, then my "hello world”.ModuleA::capitalized() and your "hello world".(capitalized from ModuleA)() are both just syntax to expose something that Swift already tracks internally.

Cheers, P

···

On Jun 7, 2016, at 10:47 AM, L. Mihalkovic via swift-evolution <swift-evolution@swift.org> wrote:

On Jun 7, 2016, at 4:53 PM, Tony Allevato <allevato@google.com <mailto:allevato@google.com>> wrote:

I like the "from" keyword the best, but I'll take my own stab at a modification:

    import ModuleA
    import ModuleB

    "hello world".(capitalized from ModuleA)()
    "hello world".(capitalized from ModuleB)()
    "hello world".(someProperty from ModuleA)
    "hello world".(someProperty from ModuleB)

Hmmm... looks like an oxymoron in its own right... I was under the impression so far that the point of extensions was that they are not tied to a source. This brings us back full circle to the very definition of extensions... However you slice it, swift is lacking some scoping bellow modules, and/or arround some of the language features.

I like the "from" keyword the best, but I'll take my own stab at a modification:

    import ModuleA
    import ModuleB

    "hello world".(capitalized from ModuleA)()
    "hello world".(capitalized from ModuleB)()
    "hello world".(someProperty from ModuleA)
    "hello world".(someProperty from ModuleB)

Hmmm... looks like an oxymoron in its own right... I was under the impression so far that the point of extensions was that they are not tied to a source. This brings us back full circle to the very definition of extensions... However you slice it, swift is lacking some scoping bellow modules, and/or arround some of the language features.

IIRC, a member of the core team (Joe Groff, maybe?) indicated several months ago on the list that methods are internally namespaced to their module. Alas, I can’t find that message. It was a long time ago.

Ah, here it is: [swift-evolution] Proposal: Universal dynamic dispatch for method calls

Joe Groff wrote:

“It's helpful to think of method names as being namespaced in Swift, by both their enclosing module and type. If two modules independently extend a protocol with a method of the same name, you still semantically have two distinct methods that dispatch independently. The extension would have to be factored into a common module both modules see for them to interact.”

IOW, yes, Swift internally does something very much like "hello world”.ModuleA::capitalized().

···

On Jun 7, 2016, at 11:36 AM, Paul Cantrell via swift-evolution <swift-evolution@swift.org> wrote:

On Jun 7, 2016, at 10:47 AM, L. Mihalkovic via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
On Jun 7, 2016, at 4:53 PM, Tony Allevato <allevato@google.com <mailto:allevato@google.com>> wrote:

You can see this in the fact that two different files can see two different extension methods:

A.swift

    import ModuleA
    …
    "hello world".capitalized()

B.swift

    import ModuleB
    …
    "hello world".capitalized()

…even if they end up compiled into the same binary. And that makes sense: A.swift only expected to see ModuleA’s extension, and was presumably coded around that expectation. That ModuleB happened to end up mixed into the same binary shouldn’t change the behavior of A.swift

If my understand is correct, then my "hello world”.ModuleA::capitalized() and your "hello world".(capitalized from ModuleA)() are both just syntax to expose something that Swift already tracks internally.

Cheers, P

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

T1 =======
import Lib1
var str = func2() // lib1

T2 =======
import Lib1
import func Lib2.func2
var str = func2() // lib2

T3 =======
import Lib1
import func Lib2.func2
var str = “str”.allCaps() // ERROR : ambiguous name

Lib1 ===========
public func func2() -> String {
  return "lib1"
}
// only during T3
public extension String {
  public func allCaps() -> String {
    return “lib1_"
  }
}

Lib2 ===========
public func func2() -> String {
  return "lib2"
}
// only during T3
public extension String {
  public func allCaps() -> String {
    return "lib2_"
  }
}

T3 shows how differently extensions are treated from all other exportable/importable artifacts: extensions are NOT sensitive to the scope of imports. they are fully loaded as soon as the loader detects that the module is referenced (they come from their own table inside the module binary).

···

On Jun 7, 2016, at 6:45 PM, Paul Cantrell <cantrell@pobox.com> wrote:

On Jun 7, 2016, at 11:36 AM, Paul Cantrell via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jun 7, 2016, at 10:47 AM, L. Mihalkovic via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jun 7, 2016, at 4:53 PM, Tony Allevato <allevato@google.com <mailto:allevato@google.com>> wrote:

I like the "from" keyword the best, but I'll take my own stab at a modification:

    import ModuleA
    import ModuleB

    "hello world".(capitalized from ModuleA)()
    "hello world".(capitalized from ModuleB)()
    "hello world".(someProperty from ModuleA)
    "hello world".(someProperty from ModuleB)

Hmmm... looks like an oxymoron in its own right... I was under the impression so far that the point of extensions was that they are not tied to a source. This brings us back full circle to the very definition of extensions... However you slice it, swift is lacking some scoping bellow modules, and/or arround some of the language features.

IIRC, a member of the core team (Joe Groff, maybe?) indicated several months ago on the list that methods are internally namespaced to their module. Alas, I can’t find that message. It was a long time ago.

Ah, here it is: [swift-evolution] Proposal: Universal dynamic dispatch for method calls

Joe Groff wrote:

“It's helpful to think of method names as being namespaced in Swift, by both their enclosing module and type. If two modules independently extend a protocol with a method of the same name, you still semantically have two distinct methods that dispatch independently. The extension would have to be factored into a common module both modules see for them to interact.”

IOW, yes, Swift internally does something very much like "hello world”.ModuleA::capitalized().

You can see this in the fact that two different files can see two different extension methods:

A.swift

    import ModuleA
    …
    "hello world".capitalized()

B.swift

    import ModuleB
    …
    "hello world".capitalized()

…even if they end up compiled into the same binary. And that makes sense: A.swift only expected to see ModuleA’s extension, and was presumably coded around that expectation. That ModuleB happened to end up mixed into the same binary shouldn’t change the behavior of A.swift

If my understand is correct, then my "hello world”.ModuleA::capitalized() and your "hello world".(capitalized from ModuleA)() are both just syntax to expose something that Swift already tracks internally.

Cheers, P

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

This would let you pick one to prefer for the entire file, but still doesn’t let you refer to both methods in the same file. I consider anything like that to be an added feature, not the core one we’re missing.

(I happen to be strongly against this change, but I don’t think it’s relevant at the moment.)

Jordan

···

On Jun 9, 2016, at 10:46, L Mihalkovic <laurent.mihalkovic@gmail.com> wrote:

On Jun 9, 2016, at 7:04 PM, Jordan Rose <jordan_rose@apple.com <mailto:jordan_rose@apple.com>> wrote:

On Jun 9, 2016, at 07:35, L. Mihalkovic <laurent.mihalkovic@gmail.com <mailto:laurent.mihalkovic@gmail.com>> wrote:

On Jun 9, 2016, at 3:27 AM, Jordan Rose via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hi, Paulo. Thanks for bringing this up; it’s definitely an interesting problem to solve.

My thoughts are mostly in line with yours, that disambiguation at the call site is the most Swift-like thing to do, at least as a first step. Maybe we can add some way to record general preferences, or maybe just asking people to define a wrapper function to put the disambiguation in one place is fine.

I’m not particularly a fan of the “from” syntax or the “@“ syntax, but I don’t have anything better. (And the “not a fan” is entirely a taste thing, plus a general desire not to steal new keywords or operator characters. Neither of these are blockers.) I’ve been playing with silly things like this:

str.(ModuleA.capitalized)()

Seeing all these proposals that people make, it makes me thinks that extensions as they exist are not fully understood... People seem to consider them like the Xtext/Xtend/c# extension METHODS, which means that maybe they should also be added to Swift, and people would not be confused:

public static func capitalized(self:String)() {}

Then these would be easily individually imported from module x,y or z with the current syntax, and then "extension String {}" would retain it current scoping behavior

No matter what, I think many extensions are just a bad outlook on OOD, but properly understood, they are great.

I’m not sure what you mean. How does changing the declaration site solve the disambiguation problem at the call site? (And how do you think Swift extensions differ from C# extensions?)

sorry, I thought the example was clearer than it actually is (pb with writing thgs in a train)

This is code I wrote a couple weeks ago (parsing some WWDC related things in C#):
namespace HtmlAgilityPackPlus {
    using HtmlAgilityPack;

    public static class Extender {
        public static HtmlNode ChildOfType(this HtmlNode node, string name) {
            var n = node.ChildNodes.Where( x => x.Name == name).First();
            return n;
        }
        public static HtmlNode FirstLink(this HtmlNode node) {
            var child = node.ChildOfType("a");
            return child;
        }
        public static HtmlNode FirstDescendantMatching(this HtmlNode node, Func<HtmlNode, bool> predicate) {
            var seq = node.Descendants().Where( x => predicate(x) );
            return ((seq?.Count() ?? 0) > 0) ? seq.First() : null;
        }
    }
}

XText and XTend work the same (I think at some point so did kotlin, but I haven’t checked since the final)

Now this is some Swift code (yes I am not bothering with the details)
module A ===

extension String {
    func oneA() { }
    func twoA() { }
    func threeA() { }
}

module B ===

extension String {
    func oneB() { }
    func twoB() { }
    func threeB() { }
}

We could say that the Swift extension is a ‘batch’ oriented mechanism:
first a target type is decided by forming a scope
then many extension methods can be added together
Of course one can also add a single method at a time in as many single scopes. But the fact remains.. the syntax is oriented towards
anonymity of the source
batch adds

as you can see, this is not how C# works.

So now, given that context, I was suggesting that people seem to consider Swift extensions as something they currently are NOT: there is no way to pinpoint a particular extension in a particular module (import the module, inherit its extensions), there is NO way to target a given method in a given extension in a given module.

My point was to suggest that it may show that current extensions are invaluable for something like the adapter pattern (than you E. Gamma), but not entirely suited for the more fine-grained scenario that people keep use in the mail thread.

This led to my proposal to ALSO support (not REPLACE)

module A ===
extension String {
    func oneA() { }
    func twoA() { }
    func threeA() { }
}
// more like the GO syntax
public static func indexOfSubStringInReversedOrder(self:String)(pattern:String) -> Int {}

module B ===
extension String {
    func oneB() { }
    func twoB() { }
    func threeB() { }
}
// more like the c#/XText/XTend/... syntax
public static func indexOfSubStringInReversedOrder(self:String, pattern:String) -> Int {}

because we can now do the following without altering anything

import func moduleA.indexOfSubStringInReversedOrder
var idx = "blahblahXYZblah".indexOfSubStringInReversedOrder("zyx")

following on my last email: see down

Hi, Paulo. Thanks for bringing this up; it’s definitely an interesting problem to solve.

My thoughts are mostly in line with yours, that disambiguation at the call site is the most Swift-like thing to do, at least as a first step. Maybe we can add some way to record general preferences, or maybe just asking people to define a wrapper function to put the disambiguation in one place is fine.

I’m not particularly a fan of the “from” syntax or the “@“ syntax, but I don’t have anything better. (And the “not a fan” is entirely a taste thing, plus a general desire not to steal new keywords or operator characters. Neither of these are blockers.) I’ve been playing with silly things like this:

str.(ModuleA.capitalized)()

Seeing all these proposals that people make, it makes me thinks that extensions as they exist are not fully understood... People seem to consider them like the Xtext/Xtend/c# extension METHODS, which means that maybe they should also be added to Swift, and people would not be confused:

public static func capitalized(self:String)() {}

Then these would be easily individually imported from module x,y or z with the current syntax, and then "extension String {}" would retain it current scoping behavior

No matter what, I think many extensions are just a bad outlook on OOD, but properly understood, they are great.

I’m not sure what you mean. How does changing the declaration site solve the disambiguation problem at the call site? (And how do you think Swift extensions differ from C# extensions?)

sorry, I thought the example was clearer than it actually is (pb with writing thgs in a train)

This is code I wrote a couple weeks ago (parsing some WWDC related things in C#):
namespace HtmlAgilityPackPlus {
    using HtmlAgilityPack;

    public static class Extender {
        public static HtmlNode ChildOfType(this HtmlNode node, string name) {
            var n = node.ChildNodes.Where( x => x.Name == name).First();
            return n;
        }
        public static HtmlNode FirstLink(this HtmlNode node) {
            var child = node.ChildOfType("a");
            return child;
        }
        public static HtmlNode FirstDescendantMatching(this HtmlNode node, Func<HtmlNode, bool> predicate) {
            var seq = node.Descendants().Where( x => predicate(x) );
            return ((seq?.Count() ?? 0) > 0) ? seq.First() : null;
        }
    }
}

XText and XTend work the same (I think at some point so did kotlin, but I haven’t checked since the final)

Now this is some Swift code (yes I am not bothering with the details)
module A ===

extension String {
    func oneA() { }
    func twoA() { }
    func threeA() { }
}

module B ===

extension String {
    func oneB() { }
    func twoB() { }
    func threeB() { }
}

We could say that the Swift extension is a ‘batch’ oriented mechanism:
first a target type is decided by forming a scope
then many extension methods can be added together
Of course one can also add a single method at a time in as many single scopes. But the fact remains.. the syntax is oriented towards
anonymity of the source
batch adds

as you can see, this is not how C# works.

So now, given that context, I was suggesting that people seem to consider Swift extensions as something they currently are NOT: there is no way to pinpoint a particular extension in a particular module (import the module, inherit its extensions), there is NO way to target a given method in a given extension in a given module.

My point was to suggest that it may show that current extensions are invaluable for something like the adapter pattern (than you E. Gamma), but not entirely suited for the more fine-grained scenario that people keep use in the mail thread.

This led to my proposal to ALSO support (not REPLACE)

module A ===
extension String {
    func oneA() { }
    func twoA() { }
    func threeA() { }
}
// more like the GO syntax
public static func indexOfSubStringInReversedOrder(self:String)(pattern:String) -> Int {}

module B ===
extension String {
    func oneB() { }
    func twoB() { }
    func threeB() { }
}
// more like the c#/XText/XTend/... syntax
public static func indexOfSubStringInReversedOrder(self:String, pattern:String) -> Int {}

because we can now do the following without altering anything

import func moduleA.indexOfSubStringInReversedOrder
var idx = "blahblahXYZblah".indexOfSubStringInReversedOrder("zyx")

then it is possible to
use extension blocks for adapter pattern / protocol compliance
use extension methods for small one-of helper bits that need precise identification

everyone happy :) - even the person writing the code in the compiler [I think the first syntax is easier to parse () () ]

···

On Jun 9, 2016, at 7:46 PM, L Mihalkovic <laurent.mihalkovic@gmail.com> wrote:

On Jun 9, 2016, at 7:04 PM, Jordan Rose <jordan_rose@apple.com <mailto:jordan_rose@apple.com>> wrote:

On Jun 9, 2016, at 07:35, L. Mihalkovic <laurent.mihalkovic@gmail.com <mailto:laurent.mihalkovic@gmail.com>> wrote:
On Jun 9, 2016, at 3:27 AM, Jordan Rose via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

// more like the GO syntax
public static func indexOfSubStringInReversedOrder(self:String)(pattern:String) -> Int {} // more parsing before being sure
public static func indexOfSubStringInReversedOrder(String)(pattern:String) -> Int {} // less parsing to identify it

Hi, Paulo. Thanks for bringing this up; it’s definitely an interesting problem to solve.

My thoughts are mostly in line with yours, that disambiguation at the call site is the most Swift-like thing to do, at least as a first step. Maybe we can add some way to record general preferences, or maybe just asking people to define a wrapper function to put the disambiguation in one place is fine.

I’m not particularly a fan of the “from” syntax or the “@“ syntax, but I don’t have anything better. (And the “not a fan” is entirely a taste thing, plus a general desire not to steal new keywords or operator characters. Neither of these are blockers.) I’ve been playing with silly things like this:

str.(ModuleA.capitalized)()

Seeing all these proposals that people make, it makes me thinks that extensions as they exist are not fully understood... People seem to consider them like the Xtext/Xtend/c# extension METHODS, which means that maybe they should also be added to Swift, and people would not be confused:

public static func capitalized(self:String)() {}

Then these would be easily individually imported from module x,y or z with the current syntax, and then "extension String {}" would retain it current scoping behavior

No matter what, I think many extensions are just a bad outlook on OOD, but properly understood, they are great.

I’m not sure what you mean. How does changing the declaration site solve the disambiguation problem at the call site? (And how do you think Swift extensions differ from C# extensions?)

sorry, I thought the example was clearer than it actually is (pb with writing thgs in a train)

This is code I wrote a couple weeks ago (parsing some WWDC related things in C#):
namespace HtmlAgilityPackPlus {
    using HtmlAgilityPack;

    public static class Extender {
        public static HtmlNode ChildOfType(this HtmlNode node, string name) {
            var n = node.ChildNodes.Where( x => x.Name == name).First();
            return n;
        }
        public static HtmlNode FirstLink(this HtmlNode node) {
            var child = node.ChildOfType("a");
            return child;
        }
        public static HtmlNode FirstDescendantMatching(this HtmlNode node, Func<HtmlNode, bool> predicate) {
            var seq = node.Descendants().Where( x => predicate(x) );
            return ((seq?.Count() ?? 0) > 0) ? seq.First() : null;
        }
    }
}

XText and XTend work the same (I think at some point so did kotlin, but I haven’t checked since the final)

Now this is some Swift code (yes I am not bothering with the details)
module A ===

extension String {
    func oneA() { }
    func twoA() { }
    func threeA() { }
}

module B ===

extension String {
    func oneB() { }
    func twoB() { }
    func threeB() { }
}

We could say that the Swift extension is a ‘batch’ oriented mechanism:
first a target type is decided by forming a scope
then many extension methods can be added together
Of course one can also add a single method at a time in as many single scopes. But the fact remains.. the syntax is oriented towards
anonymity of the source
batch adds

as you can see, this is not how C# works.

So now, given that context, I was suggesting that people seem to consider Swift extensions as something they currently are NOT: there is no way to pinpoint a particular extension in a particular module (import the module, inherit its extensions), there is NO way to target a given method in a given extension in a given module.

My point was to suggest that it may show that current extensions are invaluable for something like the adapter pattern (than you E. Gamma), but not entirely suited for the more fine-grained scenario that people keep use in the mail thread.

This led to my proposal to ALSO support (not REPLACE)

module A ===
extension String {
    func oneA() { }
    func twoA() { }
    func threeA() { }
}
// more like the GO syntax
public static func indexOfSubStringInReversedOrder(self:String)(pattern:String) -> Int {}

module B ===
extension String {
    func oneB() { }
    func twoB() { }
    func threeB() { }
}
// more like the c#/XText/XTend/... syntax
public static func indexOfSubStringInReversedOrder(self:String, pattern:String) -> Int {}

because we can now do the following without altering anything

import func moduleA.indexOfSubStringInReversedOrder
var idx = "blahblahXYZblah".indexOfSubStringInReversedOrder("zyx")
_______________________________________________

What hinders me in the case of Swift’s extensions to write

import func moduleA.String.oneB

This would achieve just the same thing.

-Thorsten

···

Am 09.06.2016 um 19:46 schrieb L Mihalkovic via swift-evolution <swift-evolution@swift.org>:

On Jun 9, 2016, at 7:04 PM, Jordan Rose <jordan_rose@apple.com <mailto:jordan_rose@apple.com>> wrote:

On Jun 9, 2016, at 07:35, L. Mihalkovic <laurent.mihalkovic@gmail.com <mailto:laurent.mihalkovic@gmail.com>> wrote:
On Jun 9, 2016, at 3:27 AM, Jordan Rose via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

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

and as you would expect …

T4 =======
import Lib1 // importing EVERYTHING from lib1
import func Lib2.func2 // importing ONLY func2 from lib2

var int1 = func1() // 1 , because lib2::func2 is not ‘visible'

—> showing again how extensions are treated differently

Lib1 ===========
public func func1() -> Int {
  return 1
}

Lib2 ===========
public func func1() -> Int {
  return 2
}

from what I saw and read, this is a rather fundamental behavior that may not be easily negotiated.

···

On Jun 7, 2016, at 8:11 PM, L Mihalkovic <laurent.mihalkovic@gmail.com> wrote:

T1 =======
import Lib1
var str = func2() // lib1

T2 =======
import Lib1
import func Lib2.func2
var str = func2() // lib2

T3 =======
import Lib1
import func Lib2.func2
var str = “str”.allCaps() // ERROR : ambiguous name

Lib1 ===========
public func func2() -> String {
  return "lib1"
}
// only during T3
public extension String {
  public func allCaps() -> String {
    return “lib1_"
  }
}

Lib2 ===========
public func func2() -> String {
  return "lib2"
}
// only during T3
public extension String {
  public func allCaps() -> String {
    return "lib2_"
  }
}

T3 shows how differently extensions are treated from all other exportable/importable artifacts: extensions are NOT sensitive to the scope of imports. they are fully loaded as soon as the loader detects that the module is referenced (they come from their own table inside the module binary).

On Jun 7, 2016, at 6:45 PM, Paul Cantrell <cantrell@pobox.com <mailto:cantrell@pobox.com>> wrote:

On Jun 7, 2016, at 11:36 AM, Paul Cantrell via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jun 7, 2016, at 10:47 AM, L. Mihalkovic via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jun 7, 2016, at 4:53 PM, Tony Allevato <allevato@google.com <mailto:allevato@google.com>> wrote:

I like the "from" keyword the best, but I'll take my own stab at a modification:

    import ModuleA
    import ModuleB

    "hello world".(capitalized from ModuleA)()
    "hello world".(capitalized from ModuleB)()
    "hello world".(someProperty from ModuleA)
    "hello world".(someProperty from ModuleB)

Hmmm... looks like an oxymoron in its own right... I was under the impression so far that the point of extensions was that they are not tied to a source. This brings us back full circle to the very definition of extensions... However you slice it, swift is lacking some scoping bellow modules, and/or arround some of the language features.

IIRC, a member of the core team (Joe Groff, maybe?) indicated several months ago on the list that methods are internally namespaced to their module. Alas, I can’t find that message. It was a long time ago.

Ah, here it is: [swift-evolution] Proposal: Universal dynamic dispatch for method calls

Joe Groff wrote:

“It's helpful to think of method names as being namespaced in Swift, by both their enclosing module and type. If two modules independently extend a protocol with a method of the same name, you still semantically have two distinct methods that dispatch independently. The extension would have to be factored into a common module both modules see for them to interact.”

IOW, yes, Swift internally does something very much like "hello world”.ModuleA::capitalized().

You can see this in the fact that two different files can see two different extension methods:

A.swift

    import ModuleA
    …
    "hello world".capitalized()

B.swift

    import ModuleB
    …
    "hello world".capitalized()

…even if they end up compiled into the same binary. And that makes sense: A.swift only expected to see ModuleA’s extension, and was presumably coded around that expectation. That ModuleB happened to end up mixed into the same binary shouldn’t change the behavior of A.swift

If my understand is correct, then my "hello world”.ModuleA::capitalized() and your "hello world".(capitalized from ModuleA)() are both just syntax to expose something that Swift already tracks internally.

Cheers, P

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

T1 =======
import Lib1
var str = func2() // lib1

T2 =======
import Lib1
import func Lib2.func2
var str = func2() // lib2

Shouldn't func2() be ambiguous here? It is imported from Lib1 and from Lib2.

-Thorsten

···

Am 07.06.2016 um 20:11 schrieb L Mihalkovic via swift-evolution <swift-evolution@swift.org>:

T3 =======
import Lib1
import func Lib2.func2
var str = “str”.allCaps() // ERROR : ambiguous name

Lib1 ===========
public func func2() -> String {
  return "lib1"
}
// only during T3
public extension String {
  public func allCaps() -> String {
    return “lib1_"
  }
}

Lib2 ===========
public func func2() -> String {
  return "lib2"
}
// only during T3
public extension String {
  public func allCaps() -> String {
    return "lib2_"
  }
}

T3 shows how differently extensions are treated from all other exportable/importable artifacts: extensions are NOT sensitive to the scope of imports. they are fully loaded as soon as the loader detects that the module is referenced (they come from their own table inside the module binary).

On Jun 7, 2016, at 6:45 PM, Paul Cantrell <cantrell@pobox.com> wrote:

On Jun 7, 2016, at 11:36 AM, Paul Cantrell via swift-evolution <swift-evolution@swift.org> wrote:

On Jun 7, 2016, at 10:47 AM, L. Mihalkovic via swift-evolution <swift-evolution@swift.org> wrote:

On Jun 7, 2016, at 4:53 PM, Tony Allevato <allevato@google.com> wrote:

I like the "from" keyword the best, but I'll take my own stab at a modification:

    import ModuleA
    import ModuleB

    "hello world".(capitalized from ModuleA)()
    "hello world".(capitalized from ModuleB)()
    "hello world".(someProperty from ModuleA)
    "hello world".(someProperty from ModuleB)

Hmmm... looks like an oxymoron in its own right... I was under the impression so far that the point of extensions was that they are not tied to a source. This brings us back full circle to the very definition of extensions... However you slice it, swift is lacking some scoping bellow modules, and/or arround some of the language features.

IIRC, a member of the core team (Joe Groff, maybe?) indicated several months ago on the list that methods are internally namespaced to their module. Alas, I can’t find that message. It was a long time ago.

Ah, here it is: [swift-evolution] Proposal: Universal dynamic dispatch for method calls

Joe Groff wrote:

“It's helpful to think of method names as being namespaced in Swift, by both their enclosing module and type. If two modules independently extend a protocol with a method of the same name, you still semantically have two distinct methods that dispatch independently. The extension would have to be factored into a common module both modules see for them to interact.”

IOW, yes, Swift internally does something very much like "hello world”.ModuleA::capitalized().

You can see this in the fact that two different files can see two different extension methods:

A.swift

    import ModuleA
    …
    "hello world".capitalized()

B.swift

    import ModuleB
    …
    "hello world".capitalized()

…even if they end up compiled into the same binary. And that makes sense: A.swift only expected to see ModuleA’s extension, and was presumably coded around that expectation. That ModuleB happened to end up mixed into the same binary shouldn’t change the behavior of A.swift

If my understand is correct, then my "hello world”.ModuleA::capitalized() and your "hello world".(capitalized from ModuleA)() are both just syntax to expose something that Swift already tracks internally.

Cheers, P

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

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

I personally consider this a longstanding bug, and would like extension member visibility to follow the same rules as top-level visibility. I don’t think that’s trivial to change, though; the lookup paths are very very different.

Jordan

···

On Jun 7, 2016, at 11:11, L Mihalkovic via swift-evolution <swift-evolution@swift.org> wrote:

T1 =======
import Lib1
var str = func2() // lib1

T2 =======
import Lib1
import func Lib2.func2
var str = func2() // lib2

T3 =======
import Lib1
import func Lib2.func2
var str = “str”.allCaps() // ERROR : ambiguous name

Lib1 ===========
public func func2() -> String {
  return "lib1"
}
// only during T3
public extension String {
  public func allCaps() -> String {
    return “lib1_"
  }
}

Lib2 ===========
public func func2() -> String {
  return "lib2"
}
// only during T3
public extension String {
  public func allCaps() -> String {
    return "lib2_"
  }
}

T3 shows how differently extensions are treated from all other exportable/importable artifacts: extensions are NOT sensitive to the scope of imports. they are fully loaded as soon as the loader detects that the module is referenced (they come from their own table inside the module binary).

Hi, Paulo. Thanks for bringing this up; it’s definitely an interesting problem to solve.

My thoughts are mostly in line with yours, that disambiguation at the call site is the most Swift-like thing to do, at least as a first step. Maybe we can add some way to record general preferences, or maybe just asking people to define a wrapper function to put the disambiguation in one place is fine.

I’m not particularly a fan of the “from” syntax or the “@“ syntax, but I don’t have anything better. (And the “not a fan” is entirely a taste thing, plus a general desire not to steal new keywords or operator characters. Neither of these are blockers.) I’ve been playing with silly things like this:

str.(ModuleA.capitalized)()

Seeing all these proposals that people make, it makes me thinks that extensions as they exist are not fully understood... People seem to consider them like the Xtext/Xtend/c# extension METHODS, which means that maybe they should also be added to Swift, and people would not be confused:

public static func capitalized(self:String)() {}

Then these would be easily individually imported from module x,y or z with the current syntax, and then "extension String {}" would retain it current scoping behavior

No matter what, I think many extensions are just a bad outlook on OOD, but properly understood, they are great.

I’m not sure what you mean. How does changing the declaration site solve the disambiguation problem at the call site? (And how do you think Swift extensions differ from C# extensions?)

sorry, I thought the example was clearer than it actually is (pb with writing thgs in a train)

This is code I wrote a couple weeks ago (parsing some WWDC related things in C#):
namespace HtmlAgilityPackPlus {
    using HtmlAgilityPack;

    public static class Extender {
        public static HtmlNode ChildOfType(this HtmlNode node, string name) {
            var n = node.ChildNodes.Where( x => x.Name == name).First();
            return n;
        }
        public static HtmlNode FirstLink(this HtmlNode node) {
            var child = node.ChildOfType("a");
            return child;
        }
        public static HtmlNode FirstDescendantMatching(this HtmlNode node, Func<HtmlNode, bool> predicate) {
            var seq = node.Descendants().Where( x => predicate(x) );
            return ((seq?.Count() ?? 0) > 0) ? seq.First() : null;
        }
    }
}

XText and XTend work the same (I think at some point so did kotlin, but I haven’t checked since the final)

Now this is some Swift code (yes I am not bothering with the details)
module A ===

extension String {
    func oneA() { }
    func twoA() { }
    func threeA() { }
}

module B ===

extension String {
    func oneB() { }
    func twoB() { }
    func threeB() { }
}

We could say that the Swift extension is a ‘batch’ oriented mechanism:
first a target type is decided by forming a scope
then many extension methods can be added together
Of course one can also add a single method at a time in as many single scopes. But the fact remains.. the syntax is oriented towards
anonymity of the source
batch adds

as you can see, this is not how C# works.

So now, given that context, I was suggesting that people seem to consider Swift extensions as something they currently are NOT: there is no way to pinpoint a particular extension in a particular module (import the module, inherit its extensions), there is NO way to target a given method in a given extension in a given module.

My point was to suggest that it may show that current extensions are invaluable for something like the adapter pattern (than you E. Gamma), but not entirely suited for the more fine-grained scenario that people keep use in the mail thread.

This led to my proposal to ALSO support (not REPLACE)

module A ===
extension String {
    func oneA() { }
    func twoA() { }
    func threeA() { }
}
// more like the GO syntax
public static func indexOfSubStringInReversedOrder(self:String)(pattern:String) -> Int {}

module B ===
extension String {
    func oneB() { }
    func twoB() { }
    func threeB() { }
}
// more like the c#/XText/XTend/... syntax
public static func indexOfSubStringInReversedOrder(self:String, pattern:String) -> Int {}

because we can now do the following without altering anything

import func moduleA.indexOfSubStringInReversedOrder
var idx = "blahblahXYZblah".indexOfSubStringInReversedOrder("zyx")
_______________________________________________

What hinders me in the case of Swift’s extensions to write

import func moduleA.String.oneB

This would achieve just the same thing.

There is also nothing preventing us from allowing named extensions in the future if compelling use cases emerge (at least one has been discussed in the past - initializing stored properties introduced in an extension). That would allow you to say something like `import extension ModuleA.String.MyExtension` or something similar to target the entire extension in one statement.

···

On Jun 9, 2016, at 1:01 PM, Thorsten Seitz via swift-evolution <swift-evolution@swift.org> wrote:

Am 09.06.2016 um 19:46 schrieb L Mihalkovic via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

On Jun 9, 2016, at 7:04 PM, Jordan Rose <jordan_rose@apple.com <mailto:jordan_rose@apple.com>> wrote:

On Jun 9, 2016, at 07:35, L. Mihalkovic <laurent.mihalkovic@gmail.com <mailto:laurent.mihalkovic@gmail.com>> wrote:
On Jun 9, 2016, at 3:27 AM, Jordan Rose via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

-Thorsten

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

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

Hi, Paulo. Thanks for bringing this up; it’s definitely an interesting problem to solve.

My thoughts are mostly in line with yours, that disambiguation at the call site is the most Swift-like thing to do, at least as a first step. Maybe we can add some way to record general preferences, or maybe just asking people to define a wrapper function to put the disambiguation in one place is fine.

I’m not particularly a fan of the “from” syntax or the “@“ syntax, but I don’t have anything better. (And the “not a fan” is entirely a taste thing, plus a general desire not to steal new keywords or operator characters. Neither of these are blockers.) I’ve been playing with silly things like this:

str.(ModuleA.capitalized)()

Seeing all these proposals that people make, it makes me thinks that extensions as they exist are not fully understood... People seem to consider them like the Xtext/Xtend/c# extension METHODS, which means that maybe they should also be added to Swift, and people would not be confused:

public static func capitalized(self:String)() {}

Then these would be easily individually imported from module x,y or z with the current syntax, and then "extension String {}" would retain it current scoping behavior

No matter what, I think many extensions are just a bad outlook on OOD, but properly understood, they are great.

I’m not sure what you mean. How does changing the declaration site solve the disambiguation problem at the call site? (And how do you think Swift extensions differ from C# extensions?)

sorry, I thought the example was clearer than it actually is (pb with writing thgs in a train)

This is code I wrote a couple weeks ago (parsing some WWDC related things in C#):
namespace HtmlAgilityPackPlus {
    using HtmlAgilityPack;

    public static class Extender {
        public static HtmlNode ChildOfType(this HtmlNode node, string name) {
            var n = node.ChildNodes.Where( x => x.Name == name).First();
            return n;
        }
        public static HtmlNode FirstLink(this HtmlNode node) {
            var child = node.ChildOfType("a");
            return child;
        }
        public static HtmlNode FirstDescendantMatching(this HtmlNode node, Func<HtmlNode, bool> predicate) {
            var seq = node.Descendants().Where( x => predicate(x) );
            return ((seq?.Count() ?? 0) > 0) ? seq.First() : null;
        }
    }
}

XText and XTend work the same (I think at some point so did kotlin, but I haven’t checked since the final)

Now this is some Swift code (yes I am not bothering with the details)
module A ===

extension String {
    func oneA() { }
    func twoA() { }
    func threeA() { }
}

module B ===

extension String {
    func oneB() { }
    func twoB() { }
    func threeB() { }
}

We could say that the Swift extension is a ‘batch’ oriented mechanism:
first a target type is decided by forming a scope
then many extension methods can be added together
Of course one can also add a single method at a time in as many single scopes. But the fact remains.. the syntax is oriented towards
anonymity of the source
batch adds

as you can see, this is not how C# works.

So now, given that context, I was suggesting that people seem to consider Swift extensions as something they currently are NOT: there is no way to pinpoint a particular extension in a particular module (import the module, inherit its extensions), there is NO way to target a given method in a given extension in a given module.

My point was to suggest that it may show that current extensions are invaluable for something like the adapter pattern (than you E. Gamma), but not entirely suited for the more fine-grained scenario that people keep use in the mail thread.

This led to my proposal to ALSO support (not REPLACE)

module A ===
extension String {
    func oneA() { }
    func twoA() { }
    func threeA() { }
}
// more like the GO syntax
public static func indexOfSubStringInReversedOrder(self:String)(pattern:String) -> Int {}

module B ===
extension String {
    func oneB() { }
    func twoB() { }
    func threeB() { }
}
// more like the c#/XText/XTend/... syntax
public static func indexOfSubStringInReversedOrder(self:String, pattern:String) -> Int {}

because we can now do the following without altering anything

import func moduleA.indexOfSubStringInReversedOrder
var idx = "blahblahXYZblah".indexOfSubStringInReversedOrder("zyx")
_______________________________________________

What hinders me in the case of Swift’s extensions to write

import func moduleA.String.oneB

This would achieve just the same thing.

hmmm….. I know… tempting, right?! but how then does this not DESTROY the other behavior?! “compiler, be smart… if I say nothing, then let the runtime loader import everything everywhere because it is still very useful even if I don’t want to recognize it right now. But then if I start to import something, then tell the runtime loader that he has to stop mocking about with all these extension blocks to String that he will find and just add the one method that I care about. and btw, remember to the other thing in all my other source files” I look forward to read the source code that will make it work, because I know I do not have the beginning of the imagination required to have a clue how it will look like.

cheers :)

···

On Jun 9, 2016, at 8:01 PM, Thorsten Seitz <tseitz42@icloud.com> wrote:

Am 09.06.2016 um 19:46 schrieb L Mihalkovic via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

On Jun 9, 2016, at 7:04 PM, Jordan Rose <jordan_rose@apple.com <mailto:jordan_rose@apple.com>> wrote:

On Jun 9, 2016, at 07:35, L. Mihalkovic <laurent.mihalkovic@gmail.com <mailto:laurent.mihalkovic@gmail.com>> wrote:
On Jun 9, 2016, at 3:27 AM, Jordan Rose via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

-Thorsten

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

T1 =======
import Lib1
var str = func2() // lib1

T2 =======
import Lib1
import func Lib2.func2
var str = func2() // lib2

Shouldn't func2() be ambiguous here? It is imported from Lib1 and from Lib2.

-Thorsten

no, that is precisely the point .. it works!! I am able to override whatever my laziness brought into scope from Lib1 (caused by my * import) with a meticulously chosen implementation from Lib2. It is brilliant. extensions on the other hand work differently (although something could undoubtedly be done about them, I cannot entirely convince myself that it is time well spent. It would be if that could be a stepping stone form something else (which I have not been able to identify so far).

···

On Jun 7, 2016, at 9:47 PM, Thorsten Seitz <tseitz42@icloud.com> wrote:
Am 07.06.2016 um 20:11 schrieb L Mihalkovic via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

T3 =======
import Lib1
import func Lib2.func2
var str = “str”.allCaps() // ERROR : ambiguous name

Lib1 ===========
public func func2() -> String {
  return "lib1"
}
// only during T3
public extension String {
  public func allCaps() -> String {
    return “lib1_"
  }
}

Lib2 ===========
public func func2() -> String {
  return "lib2"
}
// only during T3
public extension String {
  public func allCaps() -> String {
    return "lib2_"
  }
}

T3 shows how differently extensions are treated from all other exportable/importable artifacts: extensions are NOT sensitive to the scope of imports. they are fully loaded as soon as the loader detects that the module is referenced (they come from their own table inside the module binary).

On Jun 7, 2016, at 6:45 PM, Paul Cantrell <cantrell@pobox.com <mailto:cantrell@pobox.com>> wrote:

On Jun 7, 2016, at 11:36 AM, Paul Cantrell via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jun 7, 2016, at 10:47 AM, L. Mihalkovic via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jun 7, 2016, at 4:53 PM, Tony Allevato <allevato@google.com <mailto:allevato@google.com>> wrote:

I like the "from" keyword the best, but I'll take my own stab at a modification:

    import ModuleA
    import ModuleB

    "hello world".(capitalized from ModuleA)()
    "hello world".(capitalized from ModuleB)()
    "hello world".(someProperty from ModuleA)
    "hello world".(someProperty from ModuleB)

Hmmm... looks like an oxymoron in its own right... I was under the impression so far that the point of extensions was that they are not tied to a source. This brings us back full circle to the very definition of extensions... However you slice it, swift is lacking some scoping bellow modules, and/or arround some of the language features.

IIRC, a member of the core team (Joe Groff, maybe?) indicated several months ago on the list that methods are internally namespaced to their module. Alas, I can’t find that message. It was a long time ago.

Ah, here it is: [swift-evolution] Proposal: Universal dynamic dispatch for method calls

Joe Groff wrote:

“It's helpful to think of method names as being namespaced in Swift, by both their enclosing module and type. If two modules independently extend a protocol with a method of the same name, you still semantically have two distinct methods that dispatch independently. The extension would have to be factored into a common module both modules see for them to interact.”

IOW, yes, Swift internally does something very much like "hello world”.ModuleA::capitalized().

You can see this in the fact that two different files can see two different extension methods:

A.swift

    import ModuleA
    …
    "hello world".capitalized()

B.swift

    import ModuleB
    …
    "hello world".capitalized()

…even if they end up compiled into the same binary. And that makes sense: A.swift only expected to see ModuleA’s extension, and was presumably coded around that expectation. That ModuleB happened to end up mixed into the same binary shouldn’t change the behavior of A.swift

If my understand is correct, then my "hello world”.ModuleA::capitalized() and your "hello world".(capitalized from ModuleA)() are both just syntax to expose something that Swift already tracks internally.

Cheers, P

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

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

I’m thinking I’ll just go ahead and create a formal proposal with this:

Given
    ModuleA
        extension String {
            public func module() -> String {
                return "ModuleA"
            }
        }

    ModuleB
        extension String {
            public func module() -> String {
                return "ModuleB"
            }
        }

Problem
    ModuleC
        import ModuleA
        import ModuleB

        let module = "hello swift”.module() // ambiguous

Proposal
    ModuleC
        import ModuleA
        import ModuleB

        let moduleA = ("hello swift”.module() from ModuleA)
        print(moduleA) // prints "ModuleA"

        let moduleB = ("hello swift”.module() from ModuleB)
        print(moduleB) // prints "ModuleB"

        let chainingExample = ("hello swift”.module() from ModuleB).uppercased()
        print(chainingExample) // prints "MODULEB"

I'm really not sure what you're talking about. Extension methods are resolved at compile-time, not run-time. (Except @objc extension methods, which are as dangerous as categories ever were, and which isn't changing.)

Jordan

···

On Jun 9, 2016, at 11:12, L Mihalkovic <laurent.mihalkovic@gmail.com> wrote:

On Jun 9, 2016, at 8:01 PM, Thorsten Seitz <tseitz42@icloud.com <mailto:tseitz42@icloud.com>> wrote:

Am 09.06.2016 um 19:46 schrieb L Mihalkovic via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

On Jun 9, 2016, at 7:04 PM, Jordan Rose <jordan_rose@apple.com <mailto:jordan_rose@apple.com>> wrote:

On Jun 9, 2016, at 07:35, L. Mihalkovic <laurent.mihalkovic@gmail.com <mailto:laurent.mihalkovic@gmail.com>> wrote:

On Jun 9, 2016, at 3:27 AM, Jordan Rose via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hi, Paulo. Thanks for bringing this up; it’s definitely an interesting problem to solve.

My thoughts are mostly in line with yours, that disambiguation at the call site is the most Swift-like thing to do, at least as a first step. Maybe we can add some way to record general preferences, or maybe just asking people to define a wrapper function to put the disambiguation in one place is fine.

I’m not particularly a fan of the “from” syntax or the “@“ syntax, but I don’t have anything better. (And the “not a fan” is entirely a taste thing, plus a general desire not to steal new keywords or operator characters. Neither of these are blockers.) I’ve been playing with silly things like this:

str.(ModuleA.capitalized)()

Seeing all these proposals that people make, it makes me thinks that extensions as they exist are not fully understood... People seem to consider them like the Xtext/Xtend/c# extension METHODS, which means that maybe they should also be added to Swift, and people would not be confused:

public static func capitalized(self:String)() {}

Then these would be easily individually imported from module x,y or z with the current syntax, and then "extension String {}" would retain it current scoping behavior

No matter what, I think many extensions are just a bad outlook on OOD, but properly understood, they are great.

I’m not sure what you mean. How does changing the declaration site solve the disambiguation problem at the call site? (And how do you think Swift extensions differ from C# extensions?)

sorry, I thought the example was clearer than it actually is (pb with writing thgs in a train)

This is code I wrote a couple weeks ago (parsing some WWDC related things in C#):
namespace HtmlAgilityPackPlus {
    using HtmlAgilityPack;

    public static class Extender {
        public static HtmlNode ChildOfType(this HtmlNode node, string name) {
            var n = node.ChildNodes.Where( x => x.Name == name).First();
            return n;
        }
        public static HtmlNode FirstLink(this HtmlNode node) {
            var child = node.ChildOfType("a");
            return child;
        }
        public static HtmlNode FirstDescendantMatching(this HtmlNode node, Func<HtmlNode, bool> predicate) {
            var seq = node.Descendants().Where( x => predicate(x) );
            return ((seq?.Count() ?? 0) > 0) ? seq.First() : null;
        }
    }
}

XText and XTend work the same (I think at some point so did kotlin, but I haven’t checked since the final)

Now this is some Swift code (yes I am not bothering with the details)
module A ===

extension String {
    func oneA() { }
    func twoA() { }
    func threeA() { }
}

module B ===

extension String {
    func oneB() { }
    func twoB() { }
    func threeB() { }
}

We could say that the Swift extension is a ‘batch’ oriented mechanism:
first a target type is decided by forming a scope
then many extension methods can be added together
Of course one can also add a single method at a time in as many single scopes. But the fact remains.. the syntax is oriented towards
anonymity of the source
batch adds

as you can see, this is not how C# works.

So now, given that context, I was suggesting that people seem to consider Swift extensions as something they currently are NOT: there is no way to pinpoint a particular extension in a particular module (import the module, inherit its extensions), there is NO way to target a given method in a given extension in a given module.

My point was to suggest that it may show that current extensions are invaluable for something like the adapter pattern (than you E. Gamma), but not entirely suited for the more fine-grained scenario that people keep use in the mail thread.

This led to my proposal to ALSO support (not REPLACE)

module A ===
extension String {
    func oneA() { }
    func twoA() { }
    func threeA() { }
}
// more like the GO syntax
public static func indexOfSubStringInReversedOrder(self:String)(pattern:String) -> Int {}

module B ===
extension String {
    func oneB() { }
    func twoB() { }
    func threeB() { }
}
// more like the c#/XText/XTend/... syntax
public static func indexOfSubStringInReversedOrder(self:String, pattern:String) -> Int {}

because we can now do the following without altering anything

import func moduleA.indexOfSubStringInReversedOrder
var idx = "blahblahXYZblah".indexOfSubStringInReversedOrder("zyx")
_______________________________________________

What hinders me in the case of Swift’s extensions to write

import func moduleA.String.oneB

This would achieve just the same thing.

hmmm….. I know… tempting, right?! but how then does this not DESTROY the other behavior?! “compiler, be smart… if I say nothing, then let the runtime loader import everything everywhere because it is still very useful even if I don’t want to recognize it right now. But then if I start to import something, then tell the runtime loader that he has to stop mocking about with all these extension blocks to String that he will find and just add the one method that I care about. and btw, remember to the other thing in all my other source files” I look forward to read the source code that will make it work, because I know I do not have the beginning of the imagination required to have a clue how it will look like.

this is wonderful news… all this time I was under the impression that

module MyApp {
source1.swift
import moduleA
var str = “sdfa”.extensionMethod()

source2.swift
import moduleB
var str = “sdfa”.extensionMethod()
}

was a problem… but it is not, because under the hood the definition of String changes depending on which source file I am looking at. The problem only occurs when both modules are imported in the same source file. I guess I never ran into it because I only use extensions as adapters.

thx.

···

On Jun 9, 2016, at 8:14 PM, Jordan Rose <jordan_rose@apple.com> wrote:

On Jun 9, 2016, at 11:12, L Mihalkovic <laurent.mihalkovic@gmail.com <mailto:laurent.mihalkovic@gmail.com>> wrote:

On Jun 9, 2016, at 8:01 PM, Thorsten Seitz <tseitz42@icloud.com <mailto:tseitz42@icloud.com>> wrote:

Am 09.06.2016 um 19:46 schrieb L Mihalkovic via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

On Jun 9, 2016, at 7:04 PM, Jordan Rose <jordan_rose@apple.com <mailto:jordan_rose@apple.com>> wrote:

On Jun 9, 2016, at 07:35, L. Mihalkovic <laurent.mihalkovic@gmail.com <mailto:laurent.mihalkovic@gmail.com>> wrote:

On Jun 9, 2016, at 3:27 AM, Jordan Rose via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hi, Paulo. Thanks for bringing this up; it’s definitely an interesting problem to solve.

My thoughts are mostly in line with yours, that disambiguation at the call site is the most Swift-like thing to do, at least as a first step. Maybe we can add some way to record general preferences, or maybe just asking people to define a wrapper function to put the disambiguation in one place is fine.

I’m not particularly a fan of the “from” syntax or the “@“ syntax, but I don’t have anything better. (And the “not a fan” is entirely a taste thing, plus a general desire not to steal new keywords or operator characters. Neither of these are blockers.) I’ve been playing with silly things like this:

str.(ModuleA.capitalized)()

Seeing all these proposals that people make, it makes me thinks that extensions as they exist are not fully understood... People seem to consider them like the Xtext/Xtend/c# extension METHODS, which means that maybe they should also be added to Swift, and people would not be confused:

public static func capitalized(self:String)() {}

Then these would be easily individually imported from module x,y or z with the current syntax, and then "extension String {}" would retain it current scoping behavior

No matter what, I think many extensions are just a bad outlook on OOD, but properly understood, they are great.

I’m not sure what you mean. How does changing the declaration site solve the disambiguation problem at the call site? (And how do you think Swift extensions differ from C# extensions?)

sorry, I thought the example was clearer than it actually is (pb with writing thgs in a train)

This is code I wrote a couple weeks ago (parsing some WWDC related things in C#):
namespace HtmlAgilityPackPlus {
    using HtmlAgilityPack;

    public static class Extender {
        public static HtmlNode ChildOfType(this HtmlNode node, string name) {
            var n = node.ChildNodes.Where( x => x.Name == name).First();
            return n;
        }
        public static HtmlNode FirstLink(this HtmlNode node) {
            var child = node.ChildOfType("a");
            return child;
        }
        public static HtmlNode FirstDescendantMatching(this HtmlNode node, Func<HtmlNode, bool> predicate) {
            var seq = node.Descendants().Where( x => predicate(x) );
            return ((seq?.Count() ?? 0) > 0) ? seq.First() : null;
        }
    }
}

XText and XTend work the same (I think at some point so did kotlin, but I haven’t checked since the final)

Now this is some Swift code (yes I am not bothering with the details)
module A ===

extension String {
    func oneA() { }
    func twoA() { }
    func threeA() { }
}

module B ===

extension String {
    func oneB() { }
    func twoB() { }
    func threeB() { }
}

We could say that the Swift extension is a ‘batch’ oriented mechanism:
first a target type is decided by forming a scope
then many extension methods can be added together
Of course one can also add a single method at a time in as many single scopes. But the fact remains.. the syntax is oriented towards
anonymity of the source
batch adds

as you can see, this is not how C# works.

So now, given that context, I was suggesting that people seem to consider Swift extensions as something they currently are NOT: there is no way to pinpoint a particular extension in a particular module (import the module, inherit its extensions), there is NO way to target a given method in a given extension in a given module.

My point was to suggest that it may show that current extensions are invaluable for something like the adapter pattern (than you E. Gamma), but not entirely suited for the more fine-grained scenario that people keep use in the mail thread.

This led to my proposal to ALSO support (not REPLACE)

module A ===
extension String {
    func oneA() { }
    func twoA() { }
    func threeA() { }
}
// more like the GO syntax
public static func indexOfSubStringInReversedOrder(self:String)(pattern:String) -> Int {}

module B ===
extension String {
    func oneB() { }
    func twoB() { }
    func threeB() { }
}
// more like the c#/XText/XTend/... syntax
public static func indexOfSubStringInReversedOrder(self:String, pattern:String) -> Int {}

because we can now do the following without altering anything

import func moduleA.indexOfSubStringInReversedOrder
var idx = "blahblahXYZblah".indexOfSubStringInReversedOrder("zyx")
_______________________________________________

What hinders me in the case of Swift’s extensions to write

import func moduleA.String.oneB

This would achieve just the same thing.

hmmm….. I know… tempting, right?! but how then does this not DESTROY the other behavior?! “compiler, be smart… if I say nothing, then let the runtime loader import everything everywhere because it is still very useful even if I don’t want to recognize it right now. But then if I start to import something, then tell the runtime loader that he has to stop mocking about with all these extension blocks to String that he will find and just add the one method that I care about. and btw, remember to the other thing in all my other source files” I look forward to read the source code that will make it work, because I know I do not have the beginning of the imagination required to have a clue how it will look like.

I'm really not sure what you're talking about. Extension methods are resolved at compile-time, not run-time. (Except @objc extension methods, which are as dangerous as categories ever were, and which isn't changing.)

T1 =======
import Lib1
var str = func2() // lib1

T2 =======
import Lib1
import func Lib2.func2
var str = func2() // lib2

Shouldn't func2() be ambiguous here? It is imported from Lib1 and from Lib2.

-Thorsten

no, that is precisely the point .. it works!! I am able to override whatever my laziness brought into scope from Lib1 (caused by my * import) with a meticulously chosen implementation from Lib2. It is brilliant. extensions on the other hand work differently (although something could undoubtedly be done about them, I cannot entirely convince myself that it is time well spent. It would be if that could be a stepping stone form something else (which I have not been able to identify so far).

So it is dependent on the order of the imports? That’s rather fragile IMO and I would prefer having to solve clashes explicitly independent of import order, e.g. by having to hide the version from Lib1:

import Lib1 hiding func2 // strawman syntax
import func Lib2.func2

-Thorsten

···

Am 07.06.2016 um 22:27 schrieb L Mihalkovic <laurent.mihalkovic@gmail.com>:

On Jun 7, 2016, at 9:47 PM, Thorsten Seitz <tseitz42@icloud.com <mailto:tseitz42@icloud.com>> wrote:
Am 07.06.2016 um 20:11 schrieb L Mihalkovic via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

T3 =======
import Lib1
import func Lib2.func2
var str = “str”.allCaps() // ERROR : ambiguous name

Lib1 ===========
public func func2() -> String {
  return "lib1"
}
// only during T3
public extension String {
  public func allCaps() -> String {
    return “lib1_"
  }
}

Lib2 ===========
public func func2() -> String {
  return "lib2"
}
// only during T3
public extension String {
  public func allCaps() -> String {
    return "lib2_"
  }
}

T3 shows how differently extensions are treated from all other exportable/importable artifacts: extensions are NOT sensitive to the scope of imports. they are fully loaded as soon as the loader detects that the module is referenced (they come from their own table inside the module binary).

On Jun 7, 2016, at 6:45 PM, Paul Cantrell <cantrell@pobox.com <mailto:cantrell@pobox.com>> wrote:

On Jun 7, 2016, at 11:36 AM, Paul Cantrell via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jun 7, 2016, at 10:47 AM, L. Mihalkovic via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jun 7, 2016, at 4:53 PM, Tony Allevato <allevato@google.com <mailto:allevato@google.com>> wrote:

I like the "from" keyword the best, but I'll take my own stab at a modification:

    import ModuleA
    import ModuleB

    "hello world".(capitalized from ModuleA)()
    "hello world".(capitalized from ModuleB)()
    "hello world".(someProperty from ModuleA)
    "hello world".(someProperty from ModuleB)

Hmmm... looks like an oxymoron in its own right... I was under the impression so far that the point of extensions was that they are not tied to a source. This brings us back full circle to the very definition of extensions... However you slice it, swift is lacking some scoping bellow modules, and/or arround some of the language features.

IIRC, a member of the core team (Joe Groff, maybe?) indicated several months ago on the list that methods are internally namespaced to their module. Alas, I can’t find that message. It was a long time ago.

Ah, here it is: [swift-evolution] Proposal: Universal dynamic dispatch for method calls

Joe Groff wrote:

“It's helpful to think of method names as being namespaced in Swift, by both their enclosing module and type. If two modules independently extend a protocol with a method of the same name, you still semantically have two distinct methods that dispatch independently. The extension would have to be factored into a common module both modules see for them to interact.”

IOW, yes, Swift internally does something very much like "hello world”.ModuleA::capitalized().

You can see this in the fact that two different files can see two different extension methods:

A.swift

    import ModuleA
    …
    "hello world".capitalized()

B.swift

    import ModuleB
    …
    "hello world".capitalized()

…even if they end up compiled into the same binary. And that makes sense: A.swift only expected to see ModuleA’s extension, and was presumably coded around that expectation. That ModuleB happened to end up mixed into the same binary shouldn’t change the behavior of A.swift

If my understand is correct, then my "hello world”.ModuleA::capitalized() and your "hello world".(capitalized from ModuleA)() are both just syntax to expose something that Swift already tracks internally.

Cheers, P

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

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

FWIW I don't like the variant with 'from' keyword. Such syntax is too verbose for me, this syntax requires braces, I need to parse whole contents between braces to find out what is going here, we don't use words to represent hierarchy i.e. when calling methods/props of instance or referencing nested types (Type1.Type2).

IMO the best solution will be '::' as separator, so

("hello swift”.module() from ModuleA)

will be :

"hello swift”.ModuleA::module()

···

On 08.06.2016 22:50, Paulo Faria via swift-evolution wrote:

I’m thinking I’ll just go ahead and create a formal proposal with this:

Given
    ModuleA
        extension String {
            public func module() -> String {
                return "ModuleA"
            }
        }

    ModuleB
        extension String {
            public func module() -> String {
                return "ModuleB"
            }
        }

Problem
    ModuleC
        import ModuleA
        import ModuleB

        let module = "hello swift”.module() // ambiguous

Proposal
    ModuleC
        import ModuleA
        import ModuleB

        let moduleA = ("hello swift”.module() from ModuleA)
        print(moduleA) // prints "ModuleA"

        let moduleB = ("hello swift”.module() from ModuleB)
        print(moduleB) // prints "ModuleB"

        let chainingExample = ("hello swift”.module() from ModuleB).uppercased()
        print(chainingExample) // prints "MODULEB"
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

It doesn’t depend on the order, but it does consider naming a specific top-level value to be a “better” choice than importing the whole module, on the grounds that you wouldn’t have written it that way otherwise.

(I’ve been lukewarm on the entire feature of selective imports for a while since there are often a lot of helpers in the same module (think UITableView and UITableViewDataSource). We do seem to be gravitating towards making helper things nested, though (see SE-0086 <https://github.com/apple/swift-evolution/blob/master/proposals/0086-drop-foundation-ns.md&gt;\).)

This is getting a little off-topic from the problem of disambiguating members, though.

Jordan

···

On Jun 8, 2016, at 12:02, Thorsten Seitz via swift-evolution <swift-evolution@swift.org> wrote:

Am 07.06.2016 um 22:27 schrieb L Mihalkovic <laurent.mihalkovic@gmail.com <mailto:laurent.mihalkovic@gmail.com>>:

On Jun 7, 2016, at 9:47 PM, Thorsten Seitz <tseitz42@icloud.com <mailto:tseitz42@icloud.com>> wrote:

Am 07.06.2016 um 20:11 schrieb L Mihalkovic via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

T1 =======
import Lib1
var str = func2() // lib1

T2 =======
import Lib1
import func Lib2.func2
var str = func2() // lib2

Shouldn't func2() be ambiguous here? It is imported from Lib1 and from Lib2.

-Thorsten

no, that is precisely the point .. it works!! I am able to override whatever my laziness brought into scope from Lib1 (caused by my * import) with a meticulously chosen implementation from Lib2. It is brilliant. extensions on the other hand work differently (although something could undoubtedly be done about them, I cannot entirely convince myself that it is time well spent. It would be if that could be a stepping stone form something else (which I have not been able to identify so far).

So it is dependent on the order of the imports? That’s rather fragile IMO and I would prefer having to solve clashes explicitly independent of import order, e.g. by having to hide the version from Lib1:

import Lib1 hiding func2 // strawman syntax
import func Lib2.func2

T1 =======
import Lib1
var str = func2() // lib1

T2 =======
import Lib1
import func Lib2.func2
var str = func2() // lib2

Shouldn't func2() be ambiguous here? It is imported from Lib1 and from Lib2.

-Thorsten

no, that is precisely the point .. it works!! I am able to override whatever my laziness brought into scope from Lib1 (caused by my * import) with a meticulously chosen implementation from Lib2. It is brilliant. extensions on the other hand work differently (although something could undoubtedly be done about them, I cannot entirely convince myself that it is time well spent. It would be if that could be a stepping stone form something else (which I have not been able to identify so far).

So it is dependent on the order of the imports?

Swift is a c-ish derivative-ish... intentionally.

That’s rather fragile IMO and I would prefer having to solve clashes explicitly independent of import order, e.g. by having to hide the version from Lib1:

import Lib1 hiding func2 // strawman syntax
import func Lib2.func2

Interesting...

Or

Import func Lib2.func2 as func2FromLib2

···

On Jun 8, 2016, at 9:02 PM, Thorsten Seitz <tseitz42@icloud.com> wrote:

Am 07.06.2016 um 22:27 schrieb L Mihalkovic <laurent.mihalkovic@gmail.com>:
On Jun 7, 2016, at 9:47 PM, Thorsten Seitz <tseitz42@icloud.com> wrote:
Am 07.06.2016 um 20:11 schrieb L Mihalkovic via swift-evolution <swift-evolution@swift.org>:

-Thorsten

T3 =======
import Lib1
import func Lib2.func2
var str = “str”.allCaps() // ERROR : ambiguous name

Lib1 ===========
public func func2() -> String {
  return "lib1"
}
// only during T3
public extension String {
  public func allCaps() -> String {
    return “lib1_"
  }
}

Lib2 ===========
public func func2() -> String {
  return "lib2"
}
// only during T3
public extension String {
  public func allCaps() -> String {
    return "lib2_"
  }
}

T3 shows how differently extensions are treated from all other exportable/importable artifacts: extensions are NOT sensitive to the scope of imports. they are fully loaded as soon as the loader detects that the module is referenced (they come from their own table inside the module binary).

On Jun 7, 2016, at 6:45 PM, Paul Cantrell <cantrell@pobox.com> wrote:

On Jun 7, 2016, at 11:36 AM, Paul Cantrell via swift-evolution <swift-evolution@swift.org> wrote:

On Jun 7, 2016, at 10:47 AM, L. Mihalkovic via swift-evolution <swift-evolution@swift.org> wrote:

On Jun 7, 2016, at 4:53 PM, Tony Allevato <allevato@google.com> wrote:

I like the "from" keyword the best, but I'll take my own stab at a modification:

    import ModuleA
    import ModuleB

    "hello world".(capitalized from ModuleA)()
    "hello world".(capitalized from ModuleB)()
    "hello world".(someProperty from ModuleA)
    "hello world".(someProperty from ModuleB)

Hmmm... looks like an oxymoron in its own right... I was under the impression so far that the point of extensions was that they are not tied to a source. This brings us back full circle to the very definition of extensions... However you slice it, swift is lacking some scoping bellow modules, and/or arround some of the language features.

IIRC, a member of the core team (Joe Groff, maybe?) indicated several months ago on the list that methods are internally namespaced to their module. Alas, I can’t find that message. It was a long time ago.

Ah, here it is: [swift-evolution] Proposal: Universal dynamic dispatch for method calls

Joe Groff wrote:

“It's helpful to think of method names as being namespaced in Swift, by both their enclosing module and type. If two modules independently extend a protocol with a method of the same name, you still semantically have two distinct methods that dispatch independently. The extension would have to be factored into a common module both modules see for them to interact.”

IOW, yes, Swift internally does something very much like "hello world”.ModuleA::capitalized().

You can see this in the fact that two different files can see two different extension methods:

A.swift

    import ModuleA
    …
    "hello world".capitalized()

B.swift

    import ModuleB
    …
    "hello world".capitalized()

…even if they end up compiled into the same binary. And that makes sense: A.swift only expected to see ModuleA’s extension, and was presumably coded around that expectation. That ModuleB happened to end up mixed into the same binary shouldn’t change the behavior of A.swift

If my understand is correct, then my "hello world”.ModuleA::capitalized() and your "hello world".(capitalized from ModuleA)() are both just syntax to expose something that Swift already tracks internally.

Cheers, P

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

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

T1 =======
import Lib1
var str = func2() // lib1

T2 =======
import Lib1
import func Lib2.func2
var str = func2() // lib2

Shouldn't func2() be ambiguous here? It is imported from Lib1 and from Lib2.

-Thorsten

no, that is precisely the point .. it works!! I am able to override whatever my laziness brought into scope from Lib1 (caused by my * import) with a meticulously chosen implementation from Lib2. It is brilliant. extensions on the other hand work differently (although something could undoubtedly be done about them, I cannot entirely convince myself that it is time well spent. It would be if that could be a stepping stone form something else (which I have not been able to identify so far).

So it is dependent on the order of the imports? That’s rather fragile IMO and I would prefer having to solve clashes explicitly independent of import order, e.g. by having to hide the version from Lib1:

import Lib1 hiding func2 // strawman syntax
import func Lib2.func2

It doesn’t depend on the order, but it does consider naming a specific top-level value to be a “better” choice than importing the whole module, on the grounds that you wouldn’t have written it that way otherwise.

Yes, I'm sorry. i should have written my example the other way around to show that swift consistently chooses specific over implied.

···

On Jun 9, 2016, at 3:04 AM, Jordan Rose <jordan_rose@apple.com> wrote:

On Jun 8, 2016, at 12:02, Thorsten Seitz via swift-evolution <swift-evolution@swift.org> wrote:

Am 07.06.2016 um 22:27 schrieb L Mihalkovic <laurent.mihalkovic@gmail.com>:
On Jun 7, 2016, at 9:47 PM, Thorsten Seitz <tseitz42@icloud.com> wrote:
Am 07.06.2016 um 20:11 schrieb L Mihalkovic via swift-evolution <swift-evolution@swift.org>:

(I’ve been lukewarm on the entire feature of selective imports for a while since there are often a lot of helpers in the same module (think UITableView and UITableViewDataSource). We do seem to be gravitating towards making helper things nested, though (see SE-0086).)

This is getting a little off-topic from the problem of disambiguating members, though.

Jordan