Proposal: Re-instate mandatory self for accessing instance properties and functions (David Hart)

This is the full text of what Chris said in regard to “Proposal: Add Flags to Disable [Optional] Conversions"

I don’t like the idea of having different incompatible dialects, and behavior changing modes. That said, I’m personally not opposed to providing functionality that would enable people to use a reduced subsets of the language, and have the compiler enforce it. For example, I don’t have a problem with someone saying they never want to use the x!, as!, try! family and have the compiler tell them if they do.

To relate this to your question, I’d be fine with functionality that causes the compiler to produce an error when code requires an implicit conversion, but I wouldn’t want them to be just “disabled”, because I think this could change the interpretation of valid swift code (in admittedly weird cases).

In terms of how to express this, I’m not in love with modal compiler flags :-). I’d much rather this sort of requirement be specified as a pragma-like construct that applies to an arbitrary scope (e.g. class or function body) or a whole file. This keeps the code self describing.

I think the mandatory self problem is analogous to never wanting to use x!, as! or try!. If you restrict yourself to always using self.whatever, it is not unusual to someone else, and if they leave off the compiler flag or pragma that enforces this, the code will still compile.

-Kenny

···

On Dec 14, 2015, at 8:12 PM, Dennis Lysenko <dennis.s.lysenko@gmail.com> wrote:

Looks like the conversation is going in circles a bit. I believe Chris Lattner said he was opposed to any compiler flags that would lead to different dialects of Swift, and it's a valid concern, so I'm not sure how feasible an optional compiler flag would be.

On Mon, Dec 14, 2015, 8:48 PM Kenny Leung via swift-evolution <swift-evolution@swift.org> wrote:
This sounds like a candidate for a compiler option to add a warning (or error) if you leave out self. It adds no overhead to the language, but if you like it, you can enforce it.

-Kenny

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

I agree with you.

-Chris

···

On Dec 15, 2015, at 8:10 PM, Kenny Leung via swift-evolution <swift-evolution@swift.org> wrote:

This is the full text of what Chris said in regard to “Proposal: Add Flags to Disable [Optional] Conversions"

I don’t like the idea of having different incompatible dialects, and behavior changing modes. That said, I’m personally not opposed to providing functionality that would enable people to use a reduced subsets of the language, and have the compiler enforce it. For example, I don’t have a problem with someone saying they never want to use the x!, as!, try! family and have the compiler tell them if they do.

To relate this to your question, I’d be fine with functionality that causes the compiler to produce an error when code requires an implicit conversion, but I wouldn’t want them to be just “disabled”, because I think this could change the interpretation of valid swift code (in admittedly weird cases).

In terms of how to express this, I’m not in love with modal compiler flags :-). I’d much rather this sort of requirement be specified as a pragma-like construct that applies to an arbitrary scope (e.g. class or function body) or a whole file. This keeps the code self describing.

I think the mandatory self problem is analogous to never wanting to use x!, as! or try!. If you restrict yourself to always using self.whatever, it is not unusual to someone else, and if they leave off the compiler flag or pragma that enforces this, the code will still compile.

I think the mandatory self problem is analogous to never wanting to use x!, as! or try!.

For me, there is an analogy that is even more famous and that has lead to endless discussions - tabs vs. spaces:
- There are two contrary standpoints
- Many programmers have a strong opinion
- It is unlikely that both parties will ever agree
- The compiler doesn't care much about the choice

Unlike with the old indentation-problem, I think most promoters of mandatory self have to admit that there are situations where the other side is better, and many of the others would agree that "self." sometimes makes sense.
(the example with the length calculation of a vector imho really benefits from leaving out self, while I think it is good practice to include it when setting a property)
So, instead of alienating a part of the community, or burden the compiler with complex rules when to require self, I say take the "whitespace-solution" and leave the issue for style guides and tools (maybe someone can write a plugin to show or hide the "self." prefix in Xcode ;-)

My solution for mandatory self would be the status quo:
Of course it is nice to have a really detailed specification, but everyone taking a strong standpoint in this discussion should ask himself if he would prefer to decide the issue by a toss of coin or just leave everything as it is (and to make things more fair and higher the wage for the pro-self side, let's assume that it is about either having self where ever possible, or forbid it whenever the circumstances allow it).
I guess there aren't many people who would prefer the risk of the final decision — but please prove me wrong on this.

The big difference is that “!” is instantly recognizable as a code
smell (because there’s an operator which makes you feel bad for using
it) and implicit usage of “self” is not at all, (because, well, it’s
implicit). If you want to eliminate issues of force-unwrapping in your
codebase—even discounting any compiler flags—you can simply search for
the exclamation mark or use a simple regex and replace. There’s no
similar easy way to address implied self.

Indeed, both the ability to force unwrap and use of implied self can
lead to bugs, but they’re of a different variety. By force unwrapping,
you know that you’re opening up the possibility of a nil reference.
The bugs stemming from implied self are much more sneaky, bizarre, and
hard to track down (again, there is nothing that can give it away,
such as an operator).

Perhaps most importantly, any developer can make a mistake, and
despite their tendencies towards explicit self, can forget to use if
it’s a situation where its presence would prevent a bug. At least with
“?” and “!”, you’re forced to make a decision (and one of those
decisions makes you feel somewhat guilty…).

Dan

···

> On Dec 15, 2015, at 8:10 PM, Kenny Leung via swift-evolution <swift-evolution@swift.org> wrote:
> I think the mandatory self problem is analogous to never wanting to use x!, as! or try!. If you restrict yourself to always using self.whatever, it is not unusual to someone else, and if they leave off the compiler flag or pragma that enforces this, the code will still compile.

I think the mandatory self problem is analogous to never wanting to use x!, as! or try!. If you restrict yourself to always using self.whatever, it is not unusual to someone else, and if they leave off the compiler flag or pragma that enforces this, the code will still compile.

I think there is a fundamental difference between code that does / does not use x! as! or try! and code that may or may not require the use of self.

Even if you do not use x! as! or try! in your own code, you can easily read and understand code that does use those features.

But if you choose to enforce using self in your own code, suddenly you need to read and reason about code in two different ways.

In ‘mandatory self’ code, you can assume self is always being used and you cannot accidentally use something in local scope by mistake. The ‘mandatory self’ removes a set of potential bugs you need to check for when reading code. But when you encounter ’non enforced self’ code, you can’t make those assumptions and you need to check for those issues.

For me, choosing not to use x! as! or try! in your code is like choosing not to use swear words when you speak. You easily understand them when someone else uses them, but you choose not to.

Being able to choose ‘mandatory self’ or not is more like a dialect. For each dialect you need to adjust your mental model of how the language works.

Overall, I am +1 for the proposal of making self mandatory because I find the lack of 'mandatory self' makes the code less readable, less explicit as to intent and can also introduce subtle bugs.

If it comes down to adding some sort of switch or not I am -1 for that because that does seem like the creation of two dialects of the language.

James

···

On Dec 15, 2015, at 9:54 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 15, 2015, at 8:10 PM, Kenny Leung via swift-evolution <swift-evolution@swift.org> wrote:

This is the full text of what Chris said in regard to “Proposal: Add Flags to Disable [Optional] Conversions"

I don’t like the idea of having different incompatible dialects, and behavior changing modes. That said, I’m personally not opposed to providing functionality that would enable people to use a reduced subsets of the language, and have the compiler enforce it. For example, I don’t have a problem with someone saying they never want to use the x!, as!, try! family and have the compiler tell them if they do.

To relate this to your question, I’d be fine with functionality that causes the compiler to produce an error when code requires an implicit conversion, but I wouldn’t want them to be just “disabled”, because I think this could change the interpretation of valid swift code (in admittedly weird cases).

In terms of how to express this, I’m not in love with modal compiler flags :-). I’d much rather this sort of requirement be specified as a pragma-like construct that applies to an arbitrary scope (e.g. class or function body) or a whole file. This keeps the code self describing.

I think the mandatory self problem is analogous to never wanting to use x!, as! or try!. If you restrict yourself to always using self.whatever, it is not unusual to someone else, and if they leave off the compiler flag or pragma that enforces this, the code will still compile.

I agree with you.

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

I keep seeing the argument brought up that "allowing implicit self can lead
to hard to find bugs," but no one seems to be mentioning the bugs it helps
avoid. To me, it's not a tradeoff between boilerplate and bugs; it's a
tradeoff between one type of hard to find bug and another type of hard to
find bug. Let me share my own experience on both sides to clarify.

In Objective-C, self was always required, so I never encountered the
hard-to-find shadowing bugs discussed in this list. However, because self
was required everywhere, I had nothing to help me realize that using self
in a block captured self and potentially created retain cycles. These bugs
are (for me) some of the hardest to track down because memory leaks aren't
a problem until they are, and then all of a sudden potentially months of
bad practice in this area can come back to bite you all at once. And maybe
I'm just an Instruments noob, but tracking down the leak and the source of
the retain cycle was always a _huge_ pain.

Then we switched to Swift, and our team quickly adopted (and enforced
through code review) the code style where self is only allowed where it is
required. By getting in the habit of never using self, every time we write
code in a closure that implicitly captured self, the compiler would yell at
us. We learned to interpret these yells as a warning to think about memory
inside that closure, and the result has been far fewer retain-cycle bugs.

And, to be honest, in all my time using Swift (I've been writing in it
pretty much exclusively since its beta days), I can't recall a shadowing
bug that has given me much trouble at all.

So, for me (and I think I can speak for others I've worked with who also
love the reminder from the compiler to think about memory), readability
doesn't even really factor into this proposal. This proposal is mainly
about sacrificing help with avoiding very-hard-to-find bugs in retain
cycles for the sake of making easier-to-find bugs with shadowing less
likely. That is an obvious loss in my experience, and I'm hoping this
proposal won't be taken seriously until there is an alternate way for the
compiler to warn me about retain cycles.

···

On Wed, Dec 16, 2015 at 9:20 AM, James Dempsey via swift-evolution < swift-evolution@swift.org> wrote:

>> I think the mandatory self problem is analogous to never wanting to use
x!, as! or try!. If you restrict yourself to always using self.whatever, it
is not unusual to someone else, and if they leave off the compiler flag or
pragma that enforces this, the code will still compile.

I think there is a fundamental difference between code that does / does
not use x! as! or try! and code that may or may not require the use of self.

Even if you do not use x! as! or try! in your own code, you can easily
read and understand code that does use those features.

But if you choose to enforce using self in your own code, suddenly you
need to read and reason about code in two different ways.

In ‘mandatory self’ code, you can assume self is always being used and you
cannot accidentally use something in local scope by mistake. The
‘mandatory self’ removes a set of potential bugs you need to check for when
reading code. But when you encounter ’non enforced self’ code, you can’t
make those assumptions and you need to check for those issues.

For me, choosing not to use x! as! or try! in your code is like choosing
not to use swear words when you speak. You easily understand them when
someone else uses them, but you choose not to.

Being able to choose ‘mandatory self’ or not is more like a dialect. For
each dialect you need to adjust your mental model of how the language works.

Overall, I am +1 for the proposal of making self mandatory because I find
the lack of 'mandatory self' makes the code less readable, less explicit as
to intent and can also introduce subtle bugs.

If it comes down to adding some sort of switch or not I am -1 for that
because that does seem like the creation of two dialects of the language.

James

> On Dec 15, 2015, at 9:54 PM, Chris Lattner via swift-evolution < > swift-evolution@swift.org> wrote:
>
>
>> On Dec 15, 2015, at 8:10 PM, Kenny Leung via swift-evolution < > swift-evolution@swift.org> wrote:
>>
>> This is the full text of what Chris said in regard to “Proposal: Add
Flags to Disable [Optional] Conversions"
>>
>>> I don’t like the idea of having different incompatible dialects, and
behavior changing modes. That said, I’m personally not opposed to
providing functionality that would enable people to use a reduced subsets
of the language, and have the compiler enforce it. For example, I don’t
have a problem with someone saying they never want to use the x!, as!, try!
family and have the compiler tell them if they do.
>>>
>>> To relate this to your question, I’d be fine with functionality that
causes the compiler to produce an error when code requires an implicit
conversion, but I wouldn’t want them to be just “disabled”, because I think
this could change the interpretation of valid swift code (in admittedly
weird cases).
>>>
>>> In terms of how to express this, I’m not in love with modal compiler
flags :-). I’d much rather this sort of requirement be specified as a
pragma-like construct that applies to an arbitrary scope (e.g. class or
function body) or a whole file. This keeps the code self describing.
>>
>> I think the mandatory self problem is analogous to never wanting to use
x!, as! or try!. If you restrict yourself to always using self.whatever, it
is not unusual to someone else, and if they leave off the compiler flag or
pragma that enforces this, the code will still compile.
>
> I agree with you.
>
> -Chris
> _______________________________________________
> 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

Dan, +1, that is an excellent writeup of why implicit self is so dangerous.
It's exactly because it's sneaky and hard to find. Similar to bad access
errors (which, for a wealth of reasons, is impossible to "fix", but
implicit self errors ARE possible to fix.)

···

On Wed, Dec 16, 2015, 8:19 AM Dan Loewenherz via swift-evolution < swift-evolution@swift.org> wrote:

> > On Dec 15, 2015, at 8:10 PM, Kenny Leung via swift-evolution < > swift-evolution@swift.org> wrote:
> > I think the mandatory self problem is analogous to never wanting to
use x!, as! or try!. If you restrict yourself to always using
self.whatever, it is not unusual to someone else, and if they leave off the
compiler flag or pragma that enforces this, the code will still compile.

The big difference is that “!” is instantly recognizable as a code
smell (because there’s an operator which makes you feel bad for using
it) and implicit usage of “self” is not at all, (because, well, it’s
implicit). If you want to eliminate issues of force-unwrapping in your
codebase—even discounting any compiler flags—you can simply search for
the exclamation mark or use a simple regex and replace. There’s no
similar easy way to address implied self.

Indeed, both the ability to force unwrap and use of implied self can
lead to bugs, but they’re of a different variety. By force unwrapping,
you know that you’re opening up the possibility of a nil reference.
The bugs stemming from implied self are much more sneaky, bizarre, and
hard to track down (again, there is nothing that can give it away,
such as an operator).

Perhaps most importantly, any developer can make a mistake, and
despite their tendencies towards explicit self, can forget to use if
it’s a situation where its presence would prevent a bug. At least with
“?” and “!”, you’re forced to make a decision (and one of those
decisions makes you feel somewhat guilty…).

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

I think the mandatory self problem is analogous to never wanting to use x!, as! or try!. If you restrict yourself to always using self.whatever, it is not unusual to someone else, and if they leave off the compiler flag or pragma that enforces this, the code will still compile.

I think there is a fundamental difference between code that does / does not use x! as! or try! and code that may or may not require the use of self.

Even if you do not use x! as! or try! in your own code, you can easily read and understand code that does use those features.

But if you choose to enforce using self in your own code, suddenly you need to read and reason about code in two different ways.

In ‘mandatory self’ code, you can assume self is always being used and you cannot accidentally use something in local scope by mistake. The ‘mandatory self’ removes a set of potential bugs you need to check for when reading code. But when you encounter ’non enforced self’ code, you can’t make those assumptions and you need to check for those issues.

Well I always assume implicit self just as I did with Java, C++ and Objective-C (I don’t think I have ever seen any Objective-C code where the writer dutifully put "self->” in front of each ivar usage).

I think the characterising the bugs you can see from using implicit self as “sneaky and hard to find” is incorrect. I have occasionally encountered shadowing bugs, but it usually takes me about 30 seconds to realise what has gone wrong. Retain cycles on the other hand...

Overall, I am +1 for the proposal of making self mandatory because I find the lack of 'mandatory self' makes the code less readable, less explicit as to intent and can also introduce subtle bugs.

Readability is usually a subjective issue. You find not having self as less readable, probably because your brain has learned to filter out all the “self”s. I find code with unnecessary “self”s in less readable because I think they are boilerplate that obscures the logic in most situations. Neither of those outlooks are right or wrong, it depends on what you are used to.

I think we have sort of lost sight of what we are trying to achieve with this proposal. The issue is local variables shadowing properties or global variables. The author of the proposal thinks that the best way to obviate this issue is to force his particular coding style on everybody.

There are other ways to achieve the goal, for example Java has a warning that explicitly tells you when your local variable is shadowing an instance variable. Why wouldn’t that work?

···

On 16 Dec 2015, at 17:20, James Dempsey via swift-evolution <swift-evolution@swift.org> wrote:

I would also not like to see the return of mandatory self. I’d be in favor of going the opposite direction and ban even using “self” whenever it *doesn’t* disambiguate anything in the scope just to reinforce the pattern of putting self inside closures, etc and keeping things readable.

struct Foo {
  var x: Int

  func something1(x: Int) {
    print(x) // prints the incoming value, as you’d expect
    print(self.x) // prints the member var as you’d expect
  }

  func something2() {
    print(self.x) // error - x is not ambiguous, so self is not allowed!
  }
}

l8r
Sean

···

On Dec 16, 2015, at 10:47 AM, Nick Shelley via swift-evolution <swift-evolution@swift.org> wrote:

I keep seeing the argument brought up that "allowing implicit self can lead to hard to find bugs," but no one seems to be mentioning the bugs it helps avoid. To me, it's not a tradeoff between boilerplate and bugs; it's a tradeoff between one type of hard to find bug and another type of hard to find bug. Let me share my own experience on both sides to clarify.

In Objective-C, self was always required, so I never encountered the hard-to-find shadowing bugs discussed in this list. However, because self was required everywhere, I had nothing to help me realize that using self in a block captured self and potentially created retain cycles. These bugs are (for me) some of the hardest to track down because memory leaks aren't a problem until they are, and then all of a sudden potentially months of bad practice in this area can come back to bite you all at once. And maybe I'm just an Instruments noob, but tracking down the leak and the source of the retain cycle was always a _huge_ pain.

Then we switched to Swift, and our team quickly adopted (and enforced through code review) the code style where self is only allowed where it is required. By getting in the habit of never using self, every time we write code in a closure that implicitly captured self, the compiler would yell at us. We learned to interpret these yells as a warning to think about memory inside that closure, and the result has been far fewer retain-cycle bugs.

And, to be honest, in all my time using Swift (I've been writing in it pretty much exclusively since its beta days), I can't recall a shadowing bug that has given me much trouble at all.

So, for me (and I think I can speak for others I've worked with who also love the reminder from the compiler to think about memory), readability doesn't even really factor into this proposal. This proposal is mainly about sacrificing help with avoiding very-hard-to-find bugs in retain cycles for the sake of making easier-to-find bugs with shadowing less likely. That is an obvious loss in my experience, and I'm hoping this proposal won't be taken seriously until there is an alternate way for the compiler to warn me about retain cycles.

On Wed, Dec 16, 2015 at 9:20 AM, James Dempsey via swift-evolution <swift-evolution@swift.org> wrote:
>> I think the mandatory self problem is analogous to never wanting to use x!, as! or try!. If you restrict yourself to always using self.whatever, it is not unusual to someone else, and if they leave off the compiler flag or pragma that enforces this, the code will still compile.

I think there is a fundamental difference between code that does / does not use x! as! or try! and code that may or may not require the use of self.

Even if you do not use x! as! or try! in your own code, you can easily read and understand code that does use those features.

But if you choose to enforce using self in your own code, suddenly you need to read and reason about code in two different ways.

In ‘mandatory self’ code, you can assume self is always being used and you cannot accidentally use something in local scope by mistake. The ‘mandatory self’ removes a set of potential bugs you need to check for when reading code. But when you encounter ’non enforced self’ code, you can’t make those assumptions and you need to check for those issues.

For me, choosing not to use x! as! or try! in your code is like choosing not to use swear words when you speak. You easily understand them when someone else uses them, but you choose not to.

Being able to choose ‘mandatory self’ or not is more like a dialect. For each dialect you need to adjust your mental model of how the language works.

Overall, I am +1 for the proposal of making self mandatory because I find the lack of 'mandatory self' makes the code less readable, less explicit as to intent and can also introduce subtle bugs.

If it comes down to adding some sort of switch or not I am -1 for that because that does seem like the creation of two dialects of the language.

James

> On Dec 15, 2015, at 9:54 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:
>
>
>> On Dec 15, 2015, at 8:10 PM, Kenny Leung via swift-evolution <swift-evolution@swift.org> wrote:
>>
>> This is the full text of what Chris said in regard to “Proposal: Add Flags to Disable [Optional] Conversions"
>>
>>> I don’t like the idea of having different incompatible dialects, and behavior changing modes. That said, I’m personally not opposed to providing functionality that would enable people to use a reduced subsets of the language, and have the compiler enforce it. For example, I don’t have a problem with someone saying they never want to use the x!, as!, try! family and have the compiler tell them if they do.
>>>
>>> To relate this to your question, I’d be fine with functionality that causes the compiler to produce an error when code requires an implicit conversion, but I wouldn’t want them to be just “disabled”, because I think this could change the interpretation of valid swift code (in admittedly weird cases).
>>>
>>> In terms of how to express this, I’m not in love with modal compiler flags :-). I’d much rather this sort of requirement be specified as a pragma-like construct that applies to an arbitrary scope (e.g. class or function body) or a whole file. This keeps the code self describing.
>>
>> I think the mandatory self problem is analogous to never wanting to use x!, as! or try!. If you restrict yourself to always using self.whatever, it is not unusual to someone else, and if they leave off the compiler flag or pragma that enforces this, the code will still compile.
>
> I agree with you.
>
> -Chris
> _______________________________________________
> 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

The main arguments I've seen are around initializers and let-unwrapping:

    init(foo: Int) {
        self.foo = foo
    }

    guard let foo = foo else { return }

I'm curious if there are more. I think both of these could be special-cased.

Stephen

···

On Dec 17, 2015, at 4:54 AM, Jeremy Pereira via swift-evolution <swift-evolution@swift.org> wrote:

There are other ways to achieve the goal, for example Java has a warning that explicitly tells you when your local variable is shadowing an instance variable. Why wouldn’t that work?

I think the mandatory self problem is analogous to never wanting to use x!, as! or try!. If you restrict yourself to always using self.whatever, it is not unusual to someone else, and if they leave off the compiler flag or pragma that enforces this, the code will still compile.

I think there is a fundamental difference between code that does / does not use x! as! or try! and code that may or may not require the use of self.

Even if you do not use x! as! or try! in your own code, you can easily read and understand code that does use those features.

But if you choose to enforce using self in your own code, suddenly you need to read and reason about code in two different ways.

In ‘mandatory self’ code, you can assume self is always being used and you cannot accidentally use something in local scope by mistake. The ‘mandatory self’ removes a set of potential bugs you need to check for when reading code. But when you encounter ’non enforced self’ code, you can’t make those assumptions and you need to check for those issues.

Well I always assume implicit self just as I did with Java, C++ and Objective-C (I don’t think I have ever seen any Objective-C code where the writer dutifully put "self->” in front of each ivar usage).

I think the characterising the bugs you can see from using implicit self as “sneaky and hard to find” is incorrect. I have occasionally encountered shadowing bugs, but it usually takes me about 30 seconds to realise what has gone wrong. Retain cycles on the other hand…

My text was commenting on a side conversation about possibly adding a compiler flag or pragma to enforce ‘mandatory self’ or not.

I don’t think adding a such a switch for that is a good idea because I think it is more like a language dialect.

For Objective-C, accessing properties or methods always requires self. And the widely used convention to name ivars with an underbar makes it clear in those cases. Of course, there are no ivars in Swift.

I don’t think I characterized the bugs as ‘sneaky and hard to find’.

Overall, I am +1 for the proposal of making self mandatory because I find the lack of 'mandatory self' makes the code less readable, less explicit as to intent and can also introduce subtle bugs.

Readability is usually a subjective issue. You find not having self as less readable, probably because your brain has learned to filter out all the “self”s. I find code with unnecessary “self”s in less readable because I think they are boilerplate that obscures the logic in most situations. Neither of those outlooks are right or wrong, it depends on what you are used to.

Readability is definitely a subjective issue. I definitely see the self, I don’t think I filter the self out, it makes the code easier to read for me. Again, subjective.

I think we have sort of lost sight of what we are trying to achieve with this proposal. The issue is local variables shadowing properties or global variables. The author of the proposal thinks that the best way to obviate this issue is to force his particular coding style on everybody.

There are other ways to achieve the goal, for example Java has a warning that explicitly tells you when your local variable is shadowing an instance variable. Why wouldn’t that work?

If there is a warning, then you would need to change the shadowing name to get rid of the warning, because you don’t want to ship with warnings, which seems too limiting. Or you need to turn off the warning globally or for a particular file, but that means you can run into the problem accidentally in that context.

But overall, looking at the Swift API guidelines, the primary concern is clarity at the call site, with clarity taking precedence over brevity. Making self mandatory is definitely clearer at the call site, but it is less brief.

So, I think that my personal preference happens to line up with those guidelines in this case.

I don’t think we are going to change each other’s mind about this proposal, but I understand your point of view.

James

···

On Dec 17, 2015, at 1:54 AM, Jeremy Pereira <jeremy.j.pereira@googlemail.com> wrote:

On 16 Dec 2015, at 17:20, James Dempsey via swift-evolution <swift-evolution@swift.org> wrote:

In Java, I have the warning enabled for local variables but not function arguments precisely so that I can use the this.x = x pattern in constructors. The pattern is so common in Swift that I would that the init is explicitly excluded and so are the optional binding statements and guard.

···

On 17 Dec 2015, at 14:22, Stephen Celis <stephen.celis@gmail.com> wrote:

On Dec 17, 2015, at 4:54 AM, Jeremy Pereira via swift-evolution <swift-evolution@swift.org> wrote:

There are other ways to achieve the goal, for example Java has a warning that explicitly tells you when your local variable is shadowing an instance variable. Why wouldn’t that work?

The main arguments I've seen are around initializers and let-unwrapping:

    init(foo: Int) {
        self.foo = foo
    }

    guard let foo = foo else { return }

I'm curious if there are more. I think both of these could be special-cased.

Stephen

I don’t think I characterized the bugs as ‘sneaky and hard to find’.

Somebody in the thread characterised the bugs as “sneaky and hard to find” which is why I put quotes around it. Apologies for making it appear that you wrote it.

There are other ways to achieve the goal, for example Java has a warning that explicitly tells you when your local variable is shadowing an instance variable. Why wouldn’t that work?

If there is a warning, then you would need to change the shadowing name to get rid of the warning, because you don’t want to ship with warnings, which seems too limiting. Or you need to turn off the warning globally or for a particular file, but that means you can run into the problem accidentally in that context.

I don’t have a problem with renaming my local variables when they shadow instance variables in Java which happens rarely. If there isn’t a natural different name, I take that as a sign that maybe I don’t need both the local variable and the instance variable.

Java also has the option to suppress a warning for an individual function or even variable declaration through annotations.

If the objection to a bit of renaming is that it is quite onerous, generally speaking I’d rather have to rename a couple of local variables occasionally to having to put “self.” on the front of every single use of a property.

But overall, looking at the Swift API guidelines, the primary concern is clarity at the call site, with clarity taking precedence over brevity. Making self mandatory is definitely clearer at the call site, but it is less brief.

I dispute the last sentence. I think it adds unnecessary boilerplate that can obscure the intent of the code. I don’t think it adds clarity except in a few situations.

So, I think that my personal preference happens to line up with those guidelines in this case.

I don’t think we are going to change each other’s mind about this proposal, but I understand your point of view.

You’re right about that :) I have absolutely no objection whatsoever to adding compiler support for your coding style. i.e. an optional warning tat you missed “self.” off a property reference. If you want to put “self.” in front of everything, I’m fine with that, just don’t make me do it too.

···

On 17 Dec 2015, at 17:55, James Dempsey <dempsey@mac.com> wrote:

James

Simple, have the compiler require an explicit [strong self] if you use
self. inside of a closure.

···

On Wed, Dec 16, 2015 at 12:00 PM Sean Heber via swift-evolution < swift-evolution@swift.org> wrote:

I would also not like to see the return of mandatory self. I’d be in favor
of going the opposite direction and ban even using “self” whenever it
*doesn’t* disambiguate anything in the scope just to reinforce the pattern
of putting self inside closures, etc and keeping things readable.

struct Foo {
  var x: Int

  func something1(x: Int) {
    print(x) // prints the incoming value, as you’d expect
    print(self.x) // prints the member var as you’d expect
  }

  func something2() {
    print(self.x) // error - x is not ambiguous, so self is not allowed!
  }
}

l8r
Sean

> On Dec 16, 2015, at 10:47 AM, Nick Shelley via swift-evolution < > swift-evolution@swift.org> wrote:
>
> I keep seeing the argument brought up that "allowing implicit self can
lead to hard to find bugs," but no one seems to be mentioning the bugs it
helps avoid. To me, it's not a tradeoff between boilerplate and bugs; it's
a tradeoff between one type of hard to find bug and another type of hard to
find bug. Let me share my own experience on both sides to clarify.
>
> In Objective-C, self was always required, so I never encountered the
hard-to-find shadowing bugs discussed in this list. However, because self
was required everywhere, I had nothing to help me realize that using self
in a block captured self and potentially created retain cycles. These bugs
are (for me) some of the hardest to track down because memory leaks aren't
a problem until they are, and then all of a sudden potentially months of
bad practice in this area can come back to bite you all at once. And maybe
I'm just an Instruments noob, but tracking down the leak and the source of
the retain cycle was always a _huge_ pain.
>
> Then we switched to Swift, and our team quickly adopted (and enforced
through code review) the code style where self is only allowed where it is
required. By getting in the habit of never using self, every time we write
code in a closure that implicitly captured self, the compiler would yell at
us. We learned to interpret these yells as a warning to think about memory
inside that closure, and the result has been far fewer retain-cycle bugs.
>
> And, to be honest, in all my time using Swift (I've been writing in it
pretty much exclusively since its beta days), I can't recall a shadowing
bug that has given me much trouble at all.
>
> So, for me (and I think I can speak for others I've worked with who also
love the reminder from the compiler to think about memory), readability
doesn't even really factor into this proposal. This proposal is mainly
about sacrificing help with avoiding very-hard-to-find bugs in retain
cycles for the sake of making easier-to-find bugs with shadowing less
likely. That is an obvious loss in my experience, and I'm hoping this
proposal won't be taken seriously until there is an alternate way for the
compiler to warn me about retain cycles.
>
> On Wed, Dec 16, 2015 at 9:20 AM, James Dempsey via swift-evolution < > swift-evolution@swift.org> wrote:
> >> I think the mandatory self problem is analogous to never wanting to
use x!, as! or try!. If you restrict yourself to always using
self.whatever, it is not unusual to someone else, and if they leave off the
compiler flag or pragma that enforces this, the code will still compile.
>
> I think there is a fundamental difference between code that does / does
not use x! as! or try! and code that may or may not require the use of self.
>
> Even if you do not use x! as! or try! in your own code, you can easily
read and understand code that does use those features.
>
> But if you choose to enforce using self in your own code, suddenly you
need to read and reason about code in two different ways.
>
> In ‘mandatory self’ code, you can assume self is always being used and
you cannot accidentally use something in local scope by mistake. The
‘mandatory self’ removes a set of potential bugs you need to check for when
reading code. But when you encounter ’non enforced self’ code, you can’t
make those assumptions and you need to check for those issues.
>
> For me, choosing not to use x! as! or try! in your code is like
choosing not to use swear words when you speak. You easily understand them
when someone else uses them, but you choose not to.
>
> Being able to choose ‘mandatory self’ or not is more like a dialect. For
each dialect you need to adjust your mental model of how the language works.
>
> Overall, I am +1 for the proposal of making self mandatory because I
find the lack of 'mandatory self' makes the code less readable, less
explicit as to intent and can also introduce subtle bugs.
>
> If it comes down to adding some sort of switch or not I am -1 for that
because that does seem like the creation of two dialects of the language.
>
> James
>
>
> > On Dec 15, 2015, at 9:54 PM, Chris Lattner via swift-evolution < > swift-evolution@swift.org> wrote:
> >
> >
> >> On Dec 15, 2015, at 8:10 PM, Kenny Leung via swift-evolution < > swift-evolution@swift.org> wrote:
> >>
> >> This is the full text of what Chris said in regard to “Proposal: Add
Flags to Disable [Optional] Conversions"
> >>
> >>> I don’t like the idea of having different incompatible dialects, and
behavior changing modes. That said, I’m personally not opposed to
providing functionality that would enable people to use a reduced subsets
of the language, and have the compiler enforce it. For example, I don’t
have a problem with someone saying they never want to use the x!, as!, try!
family and have the compiler tell them if they do.
> >>>
> >>> To relate this to your question, I’d be fine with functionality that
causes the compiler to produce an error when code requires an implicit
conversion, but I wouldn’t want them to be just “disabled”, because I think
this could change the interpretation of valid swift code (in admittedly
weird cases).
> >>>
> >>> In terms of how to express this, I’m not in love with modal compiler
flags :-). I’d much rather this sort of requirement be specified as a
pragma-like construct that applies to an arbitrary scope (e.g. class or
function body) or a whole file. This keeps the code self describing.
> >>
> >> I think the mandatory self problem is analogous to never wanting to
use x!, as! or try!. If you restrict yourself to always using
self.whatever, it is not unusual to someone else, and if they leave off the
compiler flag or pragma that enforces this, the code will still compile.
> >
> > I agree with you.
> >
> > -Chris
> > _______________________________________________
> > 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

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

I think that this is not what Stephen meant. This `guard` statement creates a `foo` local only if `self.foo` is not nil. From there on, the unwrapped `foo` local will shadow the `foo` member.

···

Le 17 déc. 2015 à 09:20:30, Jeremy Pereira via swift-evolution <swift-evolution@swift.org> a écrit :

On 17 Dec 2015, at 14:22, Stephen Celis <stephen.celis@gmail.com> wrote:

On Dec 17, 2015, at 4:54 AM, Jeremy Pereira via swift-evolution <swift-evolution@swift.org> wrote:

There are other ways to achieve the goal, for example Java has a warning that explicitly tells you when your local variable is shadowing an instance variable. Why wouldn’t that work?

The main arguments I've seen are around initializers and let-unwrapping:

   init(foo: Int) {
       self.foo = foo
   }

   guard let foo = foo else { return }

I'm curious if there are more. I think both of these could be special-cased.

Stephen

In Java, I have the warning enabled for local variables but not function arguments precisely so that I can use the this.x = x pattern in constructors. The pattern is so common in Swift that I would that the init is explicitly excluded and so are the optional binding statements and guard.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution