Earlier quoted context omitted.
Oh, that's definitely weird then. Is there an RFC to have that fixed in some way?
I don't think there is. I think the code is functioning as expected — it's just written in a super confusing way. What should probably happen is that the compiler should throw an error about redefining a function in a super classes extension. I'm not a compiler engineer but a check for that seems like it would be intensive unless that information is codified in the AST somehow.
Swift: When Unused Code Is a Bug
21–30 of 77 posts
Re: Swift: When Unused Code Is a Bug
#22Earlier quoted context omitted.
I agree. I never worked with swift and had to look up the terminology. Most of what the article refers to maps to terms from C++ (which is already horribly complicated and offers way too many ways to shoot yourself in the foot) or Java. That PWT sounds an awful lot like a vtable. In C++ you mess up by forgetting to add "virtual" (luckily we recently got "override"), but it seems swift's protocols add another dimensio…
As someone who transitioned from Java to C#/.Net to Objective-C and finally to Swift, AMEN TO THAT! I learned not to say anything as apparently every software engineer "generation" needs to follow something "hip" when very young. Some will grow to see the cycle as it repeats itself in front of them, others will die believing "my programming language was the best, you just had to stick to this list of best practices".…
It concerns me because these are such lush, ripe targets for cargoculting. The behavior in this article is problematic exactly because of the "Apple says we must not use inheritance for anything! I can just use a protocol extension; that's totally not inheritance" mindset.
Re: Swift: When Unused Code Is a Bug
#23 public interface IGreeter {
}
public static class GreeterExtensions {
public void Greet(this IGreeter greeter) {
// If you have CA turned on,
// you'll get a warning for not
// using the parameter "greeter"
Console.WriteLine("Hello, World!");
}
}
public class BaseGreeter : IGreeter {
public abstract void Greet();
}
public class LazyGreeter : BaseGreeter {
public override void Greet() {
Console.WriteLine("sup");
}
}
IGreeter greeter = new LazyGreeter();
// This has to be GreeterExtensions.Greet(greeter),
// because IGreeter is an empty interface
greeter.Greet();
I think the syntax in C# makes it clearer that you're doing something funky mixing inheritance with extension methods. If you wanted to do it the "correct" way, I think it would look something like: public interface IGreeter {
void Greet();
}
public class BaseGreeter : IGreeter {
// Edit: abstract method wouldn't be equivalent to example
// public abstract void Greet();
public virtual void Greet() {
Console.WriteLine("Hello, World!");
}
}
public class LazyGreeter : BaseGreeter {
public override void Greet() {
Console.WriteLine("sup");
}
}
IGreeter greeter = new LazyGreeter();
greeter.Greet();
Which is more complicated than the idiomatic way of providing default behavior with inheritance: public class Greeter {
public virtual void Greet() {
Console.WriteLine("Hello, World!");
}
}
public class LazyGreeter : Greeter {
public override void Greet() {
Console.WriteLine("sup");
}
}
Greeter greeter = new LazyGreeter();
greeter.Greet();
I'm not a huge fan of the Swift syntax; specifically, IMO, the declaration `class BaseGreeter: Greeter {}` hides where the implementation of `greet` is coming from. Without the method declaration it looks like it's being inherited from the protocol extension, when it's really not.Re: Swift: When Unused Code Is a Bug
#24I can understand the advantage of using static dispatch, i.e. Greeter#greet(object), but I assume there is some mechanism that avoids calling Greeter#greet if BaseGreeter would implement greet and call BaseGreeter#greet(object) instead.
Why does extending a class which extends a protocol not make the extending class implement that protocol in Swift?
Re: Swift: When Unused Code Is a Bug
#25Re: Swift: When Unused Code Is a Bug
#26Default implementations on protocols in Swift definitely can be a little dangerous. We've shied our team away from doing this unless the protocol is explicitly used as a mix-in type. There's been some proposals around fixing these, one that comes to mind is: https://forums.swift.org/t/introducing-role-keywords-to-redu...
Re: Swift: When Unused Code Is a Bug
#27Wow, Heisen-Swift, where the Heisenbugs are in the language specification! What an object is, which is roughly equivalent to its observed behavior, should never depend on how it is declared. let greeter = LazyGreeter() let greeter1: Greeter = greeter print(greeter) print(greeter1) greeter.greet() greeter1.greet() UPDATE: just in case it's not clear, this prints the following: greeter.LazyGreeter greeter.LazyGreeter s…
Re: Swift: When Unused Code Is a Bug
#28Wow, Heisen-Swift, where the Heisenbugs are in the language specification! What an object is, which is roughly equivalent to its observed behavior, should never depend on how it is declared. let greeter = LazyGreeter() let greeter1: Greeter = greeter print(greeter) print(greeter1) greeter.greet() greeter1.greet() UPDATE: just in case it's not clear, this prints the following: greeter.LazyGreeter greeter.LazyGreeter s…
It seems this is what you get when you decide dynamic dispatch is a demon that must be cast out. :/ It's a good example of Swift's at-times-infuriating insistence on chasing performance at the expense of developer ergonomics. That said, I'm sure it will be mediated eventually (although probably with more compiler annotations).
It would be slightly less infuriating had that chase actually delivered, but it dramatically has not.
Re: Swift: When Unused Code Is a Bug
#29Wow, Heisen-Swift, where the Heisenbugs are in the language specification! What an object is, which is roughly equivalent to its observed behavior, should never depend on how it is declared. let greeter = LazyGreeter() let greeter1: Greeter = greeter print(greeter) print(greeter1) greeter.greet() greeter1.greet() UPDATE: just in case it's not clear, this prints the following: greeter.LazyGreeter greeter.LazyGreeter s…
It seems this is what you get when you decide dynamic dispatch is a demon that must be cast out. :/ It's a good example of Swift's at-times-infuriating insistence on chasing performance at the expense of developer ergonomics. That said, I'm sure it will be mediated eventually (although probably with more compiler annotations).
This is a fundamental structural issue with the language, philosophically, and will definitely cost programmer productivity. I'd argue this isn't a problem so much as behaves correctly due to insufficient planning.
It's not that they're taking a position on dynamic dispatch, it's that they're trying to take both positions, likely in support of Objective-C compatibility.
IMO dynamic dispatch has caused way more programmer productivity issues than anything else - you write code the compiler can't validate because you explicitly chose not to give it the information it needs to do it's job. It can't tell you your code is right. Nothing really can. The new world is a better place, Go and Rust have it right, inheritance is dead.
Re: Swift: When Unused Code Is a Bug
#30If I saw this in a code review, I would flag it for re-design. Mixing composition and inheritance especially in this way is definitely going to confuse anyone who doesn't read every line to figure out what's going on.
I don't think there's anything wrong with mixing composition and inheritance per se , if everything is obeying strict OOP principles (Open-Closed, etc.) If the mix-in was adding functionality to the base class, and then the subclass was there to specialize the behavior of the base class without breaking any of the contracts the base class itself makes (i.e. any unit test that works on a Greeter should work on a LazyG…