Wow, 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…
> What an object is, which is roughly equivalent to its observed behavior, should never depend on how it is declared. This is actually a statement that strong typing should not exist. A "declaration" (really a type declaration) indicates the type, and if observed behavior cannot depend on the types there is not much point to types. Or stated positively: in a strongly typed language, the types are part of 'what an obj…
Swift: When Unused Code Is a Bug
41–50 of 77 posts
Re: Swift: When Unused Code Is a Bug
#42My question to swifters: what if LazyGreeter had another method, say lazyGreet, and you typed it as Greeter? Then you called let greeter : Greeter = LazyGreeter(); greeter.lazyGreet();
Would you expect this to work or fail?
I'd expect it to fail.
In that sense, I assume its simply that extension methods override child overrides. And its just something you need to know. That can even have interesting utility in some scenarios.
Re: Swift: When Unused Code Is a Bug
#43This is an interesting demonstration of a hard edge of the language. It's not because Swift holds some sort of grudge against dynamic dispatch, but rather because it's trying to reconcile some subtly incompatible design goals: 1. Adding a default implementation for a protocol requirement shouldn't stop existing types that correctly conform to that protocol from compiling. This is a reasonable user expectation and mak…
I would disagree with that; adding that default implementation is not a simply internal change. It flat-out changes compilibility; it makes invalid code into valid code:
protocol P {
func f()
}
class C : P {} // Error!
--- protocol P {
func f()
}
extension P {
func f() {}
}
class C : P {} // Okay
Given the trap demonstrated here, the converse should hold as well. Doubly so in light of the ways the compiler (mostly helpfully) enforces various aspects of subclassing, as you pointed out.In many ways, protocols (right now at least) feel like Swift having its cake but not eating it: strictness floats around them in ways that do not help developers (ugh, PATs!) but is absent where it would:
// This all compiles without any warnings?!
protocol P {
var i: Int { get set }
}
protocol Q : P {
var i: Int { get }
}
class C : Q, P {
var i = 10
}
// Now make a protocol that inherits from another,
// where both are class/AnyObject constrained
//---
struct S : Hashable { // Swift 4.1, synthesized
let s: String
}
extension S : Equatable {
static func == (lhs: S, rhs: S) -> Bool {
// Hashable semantics, smashable semantics. Hold my beer.
return lhs.s.first == rhs.s.first
}
}Re: Swift: When Unused Code Is a Bug
#44It's just a matter of global scoping and precedence. But yeah, sharing notation between inheritance and extension is a tad bit reductionist.
Re: Swift: When Unused Code Is a Bug
#45I don't know that you can really call this a bug? It just seems to be the design choice. Though I agree, it seems odd at first, and appears possibly accidental, it could have been on purpose. My question to swifters: what if LazyGreeter had another method, say lazyGreet, and you typed it as Greeter? Then you called let greeter : Greeter = LazyGreeter(); greeter.lazyGreet(); Would you expect this to work or fail? I'd…
I concur that the behaviour is a design decision, not a bug, but I think most programmers would in general prefer design decisions to bring the language closer to python.
Re: Swift: When Unused Code Is a Bug
#46I'm reading the comments here about how the languages fails, or what it should have done better, but at the same time I'm feeling the same as I do when building up something with Kubernetes and the problem isn't really the language, it's the shortcuts we take with it to stay concise. e.g. in Kubernetes you can give a Pod, Deployment, Service, Ingress, Volume, etc. etc. the exact same name and in fact many examples en…
You make a fair point, but isn't it part of a platform's responsibility to not make footguns quite so easy to grab? Especially given Swift's general (and mostly helpful) attitude of insistence on safe, explicit constructs. For example, it's a warning to ignore a function call result; it's an error to not chain up to a superclass's initializer; it's an error to re-implement a class member without the `override` keywor…
We don't see many context-sensitive grammars for programming languages, not because very difficult to implement, but I suspect because they're hard for humans to understand.
There is something to be said for the simplicity of naming things to describe what they are (e.g. Hungarian notation), but I really think it's a mistake for languages (configuration, programming, etc.) to even allow identifiers to be reused for differing types.
Re: Swift: When Unused Code Is a Bug
#47I'm reading the comments here about how the languages fails, or what it should have done better, but at the same time I'm feeling the same as I do when building up something with Kubernetes and the problem isn't really the language, it's the shortcuts we take with it to stay concise. e.g. in Kubernetes you can give a Pod, Deployment, Service, Ingress, Volume, etc. etc. the exact same name and in fact many examples en…
I'm not sure what you mean. The only thing that's named the same is 'greet', and of course that has to be the same because it's the thing you're implementing.
Edit: Perhaps the protocol and extension could have different names? I don't see how that would make the behavior clearer.
Re: Swift: When Unused Code Is a Bug
#48Wow, 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…
> What an object is, which is roughly equivalent to its observed behavior, should never depend on how it is declared. This is actually a statement that strong typing should not exist. A "declaration" (really a type declaration) indicates the type, and if observed behavior cannot depend on the types there is not much point to types. Or stated positively: in a strongly typed language, the types are part of 'what an obj…
Prelude> a = 1
Prelude> a/2
0.5
Prelude> :t a/2
a/2 :: Fractional a => a
Prelude> b = 1 :: Int
Prelude> b/2
:6:1: error:
• No instance for (Fractional Int) arising from a use of ‘/’
• In the expression: b / 2
In an equation for ‘it’: it = b / 2
Prelude> b `div` 2
0
Prelude> :t div
div :: Integral a => a -> a -> aRe: Swift: When Unused Code Is a Bug
#49Wow, 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…
> What an object is, which is roughly equivalent to its observed behavior, should never depend on how it is declared. This is actually a statement that strong typing should not exist. A "declaration" (really a type declaration) indicates the type, and if observed behavior cannot depend on the types there is not much point to types. Or stated positively: in a strongly typed language, the types are part of 'what an obj…
> strong typing
Strong typing is not the same as static typing. `let greeter: Greeter = LazyGreeter()` is a strongly-typed `LazyGreeter`: you cannot use it where a value of another incompatible type is required, nor can you change its runtime type. But its static type is `Greeter`. Swift uses the latter for method resolution, but there's nothing inevitable or inherent about that.
`NSArray * array = [NSArray new];` is statically typed as an `NSArray`, but its dynamic (and strong) type is `__NSArray0`, and that's where the value's implementations come from.
> they model the same underlying mathematical concept
They don't: one models an integral and the other models(/approximates) a real. Which is why, as another commentor already pointed out, they're not `==`.
Re: Swift: When Unused Code Is a Bug
#50Earlier quoted context omitted.
You make a fair point, but isn't it part of a platform's responsibility to not make footguns quite so easy to grab? Especially given Swift's general (and mostly helpful) attitude of insistence on safe, explicit constructs. For example, it's a warning to ignore a function call result; it's an error to not chain up to a superclass's initializer; it's an error to re-implement a class member without the `override` keywor…
The problem with this angle is that while sure, you can always make a compiler more intelligent in ambiguous situations, you must also now train all the humans interfacing with it to be equally as intelligent (or at least, able to sufficiently disambiguate). We don't see many context-sensitive grammars for programming languages, not because very difficult to implement, but I suspect because they're hard for humans to…
I'm not sure what you mean here; probably I'm misunderstanding you somehow.
If you make the compiler more intelligent so that it can tell the humans about subtle problems, that lets the humans be less intelligent (or at least have to think less). No?