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


(Paulo Faria) #1

Hello, everyone.

I want to discuss the problem of name ambiguity when a computed property or function is defined with the same name and type in different modules. Currently there’s no way to disambiguate the implementation in use cases similar to the one contained in the gist below.

https://gist.github.com/paulofaria/f48d0b847a0fb7c125d163d0e349500a

The gist also contains some informal proposals. The idea is to create a formal proposal based on the discussion that shall follow.

Cheers,
Paulo


(Brad Hilton) #2

+1. I agree that this could be a problem, especially if you’re importing a lot of similar modules. I like the `from` keyword, as I feel that is consistent with the language grammer. My vote would be for proposal #4.

···

Hello, everyone.

I want to discuss the problem of name ambiguity when a computed property or function is defined with the same name and type in different modules. Currently there’s no way to disambiguate the implementation in use cases similar to the one contained in the gist below.

https://gist.github.com/paulofaria/f48d0b847a0fb7c125d163d0e349500a

The gist also contains some informal proposals. The idea is to create a formal proposal based on the discussion that shall follow.

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


(David Sweeris) #3

You forgot one :slight_smile:
let capitalizedA = ModuleA {
    "hello swift".capitalized()
}

+1 on finding a way to explicitly resolve naming collisions. I'm generally in favor of something like #2 (or #3). A while back, there was a proposal to replace numerical operator precedence with a relative precedence system. I can't remember if it went through, but if so I would argue that the two systems should probably be the same, since they solve the same problem.

I would also suggest there be a way to import a module at a lower precedence than the current source file, for the purposes of "overriding" any top-level functions (or even types, I suppose).

Something like "partially import ModuleA" would solve the problem as well, but I can't think of anything resembling a practical syntax for specifying which parts.

- Dave Sweeris

···

On Jun 4, 2016, at 20:29, Paulo Faria via swift-evolution <swift-evolution@swift.org> wrote:

Hello, everyone.

I want to discuss the problem of name ambiguity when a computed property or function is defined with the same name and type in different modules. Currently there’s no way to disambiguate the implementation in use cases similar to the one contained in the gist below.

https://gist.github.com/paulofaria/f48d0b847a0fb7c125d163d0e349500a

The gist also contains some informal proposals. The idea is to create a formal proposal based on the discussion that shall follow.

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


(L Mihalkovic) #4

IMO you have identified some of the symptoms of a larger issue with Swift.

Currently swift lets us group our code into modules. Within a module we can use folders to physically group the files, but this is not mandatory (and xcode does not by default align the logical and physical structure of a project). My observation of most github projects i read is that people struggle to organize the code, often resorting to adopting a black-socks with black-socks approach (extensions together, structs together...).

The result is that swift is great for small apps or libraries, but not so much for large amounts of code written by several people, when compared to what can be done with scala, java, c++, c#, kotlin, and even typescript.

Rather than the proposed solution, I would much rather see swift acquire sub-scoping inside modules (call it sub module or namespace) with local imports. I think addressing the symptomes by prioritizing imports will only make it easier to write more disorganized code.

···

On Jun 5, 2016, at 3:29 AM, Paulo Faria via swift-evolution <swift-evolution@swift.org> wrote:

Hello, everyone.

I want to discuss the problem of name ambiguity when a computed property or function is defined with the same name and type in different modules. Currently there’s no way to disambiguate the implementation in use cases similar to the one contained in the gist below.

https://gist.github.com/paulofaria/f48d0b847a0fb7c125d163d0e349500a

The gist also contains some informal proposals. The idea is to create a formal proposal based on the discussion that shall follow.

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


(Paulo Faria) #5

Actually I don’t like the prioritization of the modules import. I’m much more in favor of disambiguating at call site. like we have to do in any other case of ambiguity in Swift. The concept of precedence is only present in operators and that makes sense because it’s in their nature. I think #4 or #5 or any other way to disambiguate at call site would be the most appropriate.

···

On Jun 4, 2016, at 10:29 PM, Paulo Faria <paulo@zewo.io> wrote:

Hello, everyone.

I want to discuss the problem of name ambiguity when a computed property or function is defined with the same name and type in different modules. Currently there’s no way to disambiguate the implementation in use cases similar to the one contained in the gist below.

https://gist.github.com/paulofaria/f48d0b847a0fb7c125d163d0e349500a

The gist also contains some informal proposals. The idea is to create a formal proposal based on the discussion that shall follow.

Cheers,
Paulo


(Brent Royal-Gordon) #6

I want to discuss the problem of name ambiguity when a computed property or function is defined with the same name and type in different modules. Currently there’s no way to disambiguate the implementation in use cases similar to the one contained in the gist below.

https://gist.github.com/paulofaria/f48d0b847a0fb7c125d163d0e349500a

The gist also contains some informal proposals. The idea is to create a formal proposal based on the discussion that shall follow.

We already have the concept of prefixing a type name with a module to disambiguate when two modules have the same type. I wonder if we could do the same thing to disambiguate between conflicting extensions?

  import ModuleA
  import ModuleB
  
  ("hello world" as ModuleA.String).capitalized() // Swift.String, with only APIs known to ModuleA
  ("hello world" as ModuleB.String).capitalized() // Swift.String, with only APIs known to ModuleB
  "hello world".capitalized() // Still causes a compile-time error for ambiguity

···

--
Brent Royal-Gordon
Architechies


(L Mihalkovic) #7

I want to discuss the problem of name ambiguity when a computed property or function is defined with the same name and type in different modules. Currently there’s no way to disambiguate the implementation in use cases similar to the one contained in the gist below.

https://gist.github.com/paulofaria/f48d0b847a0fb7c125d163d0e349500a

The gist also contains some informal proposals. The idea is to create a formal proposal based on the discussion that shall follow.

We already have the concept of prefixing a type name with a module to disambiguate when two modules have the same type. I wonder if we could do the same thing to disambiguate between conflicting extensions?

   import ModuleA
   import ModuleB
   
   ("hello world" as ModuleA.String).capitalized() // Swift.String, with only APIs known to ModuleA
   ("hello world" as ModuleB.String).capitalized() // Swift.String, with only APIs known to ModuleB
   "hello world".capitalized() // Still causes a compile-time error for ambiguity

That is one furious rewrite of the compiler/runtime (module loader, compliance table storage/dynamic resolution ... ), starting with the fact that extensions do not have scopes and are not even types

···

--
Brent Royal-Gordon
Architechies

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


(Charlie Monroe) #8

We already have the concept of prefixing a type name with a module to disambiguate when two modules have the same type. I wonder if we could do the same thing to disambiguate between conflicting extensions?

  import ModuleA
  import ModuleB
  
  ("hello world" as ModuleA.String).capitalized() // Swift.String, with only APIs known to ModuleA
  ("hello world" as ModuleB.String).capitalized() // Swift.String, with only APIs known to ModuleB
  "hello world".capitalized() // Still causes a compile-time error for ambiguity

This only introduces a new kind of ambiguity since you can have both ModuleA and ModuleB declare something like

class String {
  /// ...
}

And now you have no idea if ModuleA.String refers to Swift.String extension in ModuleA or class String in ModuleA.

···

--
Brent Royal-Gordon
Architechies

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


(Jordan Rose) #9

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)()

which I think has come up on-thread already. (It’s close to Paul’s '::', anyway.)

A bonus is if we can use this same thing for globals. We have a problem today where “Foo.Bar” can’t refer to a member of a module if there’s also a type named “Foo”; changing the syntax to “Foo::Bar” or “Bar from Foo” (or adding it as an alternative) would solve that problem and provide consistency.

Sorry I don’t have anything too conclusive to add. My last point is that while we do have a problem today, it’s a problem we’ve lived with for two years, and any features we add to solve it are additive. That means it’s okay if we don’t come up with an answer in Swift 3.

Jordan

···

On Jun 6, 2016, at 06:47, Paulo Faria via swift-evolution <swift-evolution@swift.org> wrote:

Actually I don’t like the prioritization of the modules import. I’m much more in favor of disambiguating at call site. like we have to do in any other case of ambiguity in Swift. The concept of precedence is only present in operators and that makes sense because it’s in their nature. I think #4 or #5 or any other way to disambiguate at call site would be the most appropriate.

On Jun 4, 2016, at 10:29 PM, Paulo Faria <paulo@zewo.io <mailto:paulo@zewo.io>> wrote:

Hello, everyone.

I want to discuss the problem of name ambiguity when a computed property or function is defined with the same name and type in different modules. Currently there’s no way to disambiguate the implementation in use cases similar to the one contained in the gist below.

https://gist.github.com/paulofaria/f48d0b847a0fb7c125d163d0e349500a

The gist also contains some informal proposals. The idea is to create a formal proposal based on the discussion that shall follow.

Cheers,
Paulo

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


(Paul Cantrell) #10

Perhaps the disambiguation should be on the extension method, not the type:

  import ModuleA
  import ModuleB
  
  "hello world”.ModuleA::capitalized()
  "hello world”.ModuleB::capitalized()

(Insert your own namespace separator if :: gives you unpleasant C++ flashbacks.)

P

···

On Jun 7, 2016, at 7:09 AM, Charlie Monroe via swift-evolution <swift-evolution@swift.org> wrote:

We already have the concept of prefixing a type name with a module to disambiguate when two modules have the same type. I wonder if we could do the same thing to disambiguate between conflicting extensions?

  import ModuleA
  import ModuleB
  
  ("hello world" as ModuleA.String).capitalized() // Swift.String, with only APIs known to ModuleA
  ("hello world" as ModuleB.String).capitalized() // Swift.String, with only APIs known to ModuleB
  "hello world".capitalized() // Still causes a compile-time error for ambiguity

This only introduces a new kind of ambiguity since you can have both ModuleA and ModuleB declare something like

class String {
  /// ...
}

And now you have no idea if ModuleA.String refers to Swift.String extension in ModuleA or class String in ModuleA.


(L Mihalkovic) #11

We already have the concept of prefixing a type name with a module to disambiguate when two modules have the same type. I wonder if we could do the same thing to disambiguate between conflicting extensions?

   import ModuleA
   import ModuleB
   
   ("hello world" as ModuleA.String).capitalized() // Swift.String, with only APIs known to ModuleA
   ("hello world" as ModuleB.String).capitalized() // Swift.String, with only APIs known to ModuleB
   "hello world".capitalized() // Still causes a compile-time error for ambiguity

This only introduces a new kind of ambiguity since you can have both ModuleA and ModuleB declare something like

class String {
   /// ...
}

And now you have no idea if ModuleA.String refers to Swift.String extension in ModuleA or class String in ModuleA.

Keep in mind that extensions are not types. (See prev response)

···

--
Brent Royal-Gordon
Architechies

_______________________________________________
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


(L Mihalkovic) #12

C# has scoped imports to deal with this. I like it... (I went back to c# until swift 3 or 4 get more feature complete).

Regards
(From mobile)

···

On Jun 9, 2016, at 3:27 AM, Jordan Rose via swift-evolution <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)()

which I think has come up on-thread already. (It’s close to Paul’s '::', anyway.)

A bonus is if we can use this same thing for globals. We have a problem today where “Foo.Bar” can’t refer to a member of a module if there’s also a type named “Foo”; changing the syntax to “Foo::Bar” or “Bar from Foo” (or adding it as an alternative) would solve that problem and provide consistency.

Sorry I don’t have anything too conclusive to add. My last point is that while we do have a problem today, it’s a problem we’ve lived with for two years, and any features we add to solve it are additive. That means it’s okay if we don’t come up with an answer in Swift 3.

Jordan

On Jun 6, 2016, at 06:47, Paulo Faria via swift-evolution <swift-evolution@swift.org> wrote:

Actually I don’t like the prioritization of the modules import. I’m much more in favor of disambiguating at call site. like we have to do in any other case of ambiguity in Swift. The concept of precedence is only present in operators and that makes sense because it’s in their nature. I think #4 or #5 or any other way to disambiguate at call site would be the most appropriate.

On Jun 4, 2016, at 10:29 PM, Paulo Faria <paulo@zewo.io> wrote:

Hello, everyone.

I want to discuss the problem of name ambiguity when a computed property or function is defined with the same name and type in different modules. Currently there’s no way to disambiguate the implementation in use cases similar to the one contained in the gist below.

https://gist.github.com/paulofaria/f48d0b847a0fb7c125d163d0e349500a

The gist also contains some informal proposals. The idea is to create a formal proposal based on the discussion that shall follow.

Cheers,
Paulo

_______________________________________________
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


(Paulo Faria) #13

A bonus is if we can use this same thing for globals. We have a problem today where “Foo.Bar” can’t refer to a member of a module if there’s also a type named “Foo”; changing the syntax to “Foo::Bar” or “Bar from Foo” (or adding it as an alternative) would solve that problem and provide consistency.

So you mean the syntax for module namespacing would be “::” for everything? Yeah that would probably solve some other related problems as well. I’m not very fond of the “::” separator. But yeah, I think a different separator would be better than the “from” keyword, then. Maybe we can come up with a nicer separator? the options I can think of are (in order of preference):

Foo:Bar
Foo::Bar
Foo#Bar
Foo@Bar

Anything too different from this would be too exotic. Would there be too much problem with a single colon “:”?

struct Baz: Foo:Bar {
  ...
}

let dictionary: [Swift:String: Foo:Bar] = [:]

I’m sensing yes. :frowning:


(L Mihalkovic) #14

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.

···

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

which I think has come up on-thread already. (It’s close to Paul’s '::', anyway.)

A bonus is if we can use this same thing for globals. We have a problem today where “Foo.Bar” can’t refer to a member of a module if there’s also a type named “Foo”; changing the syntax to “Foo::Bar” or “Bar from Foo” (or adding it as an alternative) would solve that problem and provide consistency.

Sorry I don’t have anything too conclusive to add. My last point is that while we do have a problem today, it’s a problem we’ve lived with for two years, and any features we add to solve it are additive. That means it’s okay if we don’t come up with an answer in Swift 3.

Jordan

On Jun 6, 2016, at 06:47, Paulo Faria via swift-evolution <swift-evolution@swift.org> wrote:

Actually I don’t like the prioritization of the modules import. I’m much more in favor of disambiguating at call site. like we have to do in any other case of ambiguity in Swift. The concept of precedence is only present in operators and that makes sense because it’s in their nature. I think #4 or #5 or any other way to disambiguate at call site would be the most appropriate.

On Jun 4, 2016, at 10:29 PM, Paulo Faria <paulo@zewo.io> wrote:

Hello, everyone.

I want to discuss the problem of name ambiguity when a computed property or function is defined with the same name and type in different modules. Currently there’s no way to disambiguate the implementation in use cases similar to the one contained in the gist below.

https://gist.github.com/paulofaria/f48d0b847a0fb7c125d163d0e349500a

The gist also contains some informal proposals. The idea is to create a formal proposal based on the discussion that shall follow.

Cheers,
Paulo

_______________________________________________
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


(Tony Allevato) #15

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)

The "from" keyword makes it clearer than arbitrary punctuation what's going
on, and extending the member reference syntax to support ".(member from
Module)" seems clearer than putting the "from Module" after the actual
call; we're saying "look up the member named 'member' on the receiver's
type inside Module", as opposed to having it look like the "from" applies
to the *expression*, which it doesn't.

Having the parens there is helpful in the property disambiguating case,
where we would otherwise have this:

    "hello world".someProperty from ModuleB.bar

Is that a property "bar" on the result of "someProperty" from ModuleB, or
is that "someProperty" from submodule ModuleB.bar? This removes the
ambiguity:

    "hello world".(someProperty from ModuleB).bar

···

On Tue, Jun 7, 2016 at 7:27 AM LM via swift-evolution < swift-evolution@swift.org> wrote:

>> We already have the concept of prefixing a type name with a module to
disambiguate when two modules have the same type. I wonder if we could do
the same thing to disambiguate between conflicting extensions?
>>
>> import ModuleA
>> import ModuleB
>>
>> ("hello world" as ModuleA.String).capitalized() // Swift.String,
with only APIs known to ModuleA
>> ("hello world" as ModuleB.String).capitalized() // Swift.String,
with only APIs known to ModuleB
>> "hello world".capitalized() // Still causes a
compile-time error for ambiguity
>
> This only introduces a new kind of ambiguity since you can have both
ModuleA and ModuleB declare something like
>
> class String {
> /// ...
> }
>
> And now you have no idea if ModuleA.String refers to Swift.String
extension in ModuleA or class String in ModuleA.
>

Keep in mind that extensions are not types. (See prev response)

>
>
>>
>> --
>> Brent Royal-Gordon
>> Architechies
>>
>> _______________________________________________
>> 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
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(L Mihalkovic) #16

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.

···

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

The "from" keyword makes it clearer than arbitrary punctuation what's going on, and extending the member reference syntax to support ".(member from Module)" seems clearer than putting the "from Module" after the actual call; we're saying "look up the member named 'member' on the receiver's type inside Module", as opposed to having it look like the "from" applies to the *expression*, which it doesn't.

Having the parens there is helpful in the property disambiguating case, where we would otherwise have this:

    "hello world".someProperty from ModuleB.bar

Is that a property "bar" on the result of "someProperty" from ModuleB, or is that "someProperty" from submodule ModuleB.bar? This removes the ambiguity:

    "hello world".(someProperty from ModuleB).bar

On Tue, Jun 7, 2016 at 7:27 AM LM via swift-evolution <swift-evolution@swift.org> wrote:

>> We already have the concept of prefixing a type name with a module to disambiguate when two modules have the same type. I wonder if we could do the same thing to disambiguate between conflicting extensions?
>>
>> import ModuleA
>> import ModuleB
>>
>> ("hello world" as ModuleA.String).capitalized() // Swift.String, with only APIs known to ModuleA
>> ("hello world" as ModuleB.String).capitalized() // Swift.String, with only APIs known to ModuleB
>> "hello world".capitalized() // Still causes a compile-time error for ambiguity
>
> This only introduces a new kind of ambiguity since you can have both ModuleA and ModuleB declare something like
>
> class String {
> /// ...
> }
>
> And now you have no idea if ModuleA.String refers to Swift.String extension in ModuleA or class String in ModuleA.
>

Keep in mind that extensions are not types. (See prev response)

>
>
>>
>> --
>> Brent Royal-Gordon
>> Architechies
>>
>> _______________________________________________
>> 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
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Jordan Rose) #17

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?)

Jordan

···

On Jun 9, 2016, at 07:35, L. Mihalkovic <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.


(Paulo Faria) #18

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

Care to explain a bit more what you mean with this? What is the improper “understandment” and what would be the proper “understandment”?


(L Mihalkovic) #19

IMVHO much of the extension code I saw was people cramming a lot of their business code inside UIView derivative extensions. Another use case I saw a lot was utility methods following the pattern of
  “http://www.whattheheck.com
      .connect()
      .lookMaIcanWriteAnEntire()
      .applicationWithout()
      .havingTo()
      .promise(ToThinkTooMuch().aboutIt());

this is just an illustration, but we have all seen this, right?!

···

On Jun 9, 2016, at 4:41 PM, Paulo Faria <paulo@zewo.io> wrote:

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

Care to explain a bit more what you mean with this? What is the improper “understandment” and what would be the proper “understandment”?


(L Mihalkovic) #20

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")

···

On Jun 9, 2016, at 7:04 PM, Jordan Rose <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?)