I am trying to figure out why I am having constant compile problems with this type of construct in Xcode 6.3.2.
class Foo {
static let CONSTANT_NAME = "CONSTANT_STRING"
...
func bar () -> String {
var s = String(format:"%s,%d\n", CONSTANT_NAME, 7)
return s
}
...
}
As I understand the language, this should be perfectly legal code however Xcode is constantly (hah-pun) having issues with it raising the error
"there is no member CONSTANT_NAME in class Foo"
If I get lucky and force it to clean, and then rebuild it will some times sort itself out and work. Other times, even doing that, then trying an open/close project will still not resolve the issue.
So, I guess my implicit follow up question (if the answer to the above is - it is legal code) is: is the Xcode Swift compiler that buggy that even basic things like this are likely to cause problems? If so, swift seems to be in a pretty bad state.
static is class property, that means you have to call it like this ClassName.property
class Foo {
static let CONSTANT_NAME = "CONSTANT_STRING"
func bar () -> String {
var s = String(format:"%s,%d\n", Foo.CONSTANT_NAME, 7)
return s
}
}
That is not a bug. That is what it should be. A class property "belongs" to the class.
If you want your code work without using ClassName, do not use static
class Foo {
let CONSTANT_NAME = "CONSTANT_STRING"
func bar () -> String {
var s = String(format:"%s,%d\n",CONSTANT_NAME, 7)
return s
}
}
More details in the Apple Documentation
The static let syntax is legal and valid. The issue is that you must fully qualify that variable when you access it:
var s = String(format:"%s,%d\n", Foo.CONSTANT_NAME, 7)
The compiler error is a bit obtuse, but it is telling the truth... CONSTANT_NAME is not a member, but a type property of class Foo: Swift Type Properties
I hear you about saving key strokes. I've personally been trying to make my Swift code as idiomatic as possible by milking every short cuts but when you find code like this, you should be glad that the compiler asks you to keep on the safe side:
class Foo {
static let CONSTANT = "hello"
func bar() -> String {
let CONSTANT = "bye"
return CONSTANT // I know which one! Thanks Swift!
}
}
println(Foo.CONSTANT)
println(Foo().bar())
Related
I am not sure if it is a bug or it is really how things should work?
class A {
init() throws { }
}
class B {
lazy var instance = A()
}
this code compiles without mistakes using XCode 9 and latest Swift version, and works perfect unless Class A init() really throws, then lazy var is null pointer. But shouldn't be this code somehow not be compiled?
This is indeed a bug (SR-7862) – you cannot throw errors out of a property initialiser context (and even if you could, you would be required to prefix the call with try), therefore the compiler should produce an error.
I have opened a pull request to fix this (#17022).
Edit: The patch has now been cherry-picked to the 4.2 branch, so it'll be fixed for the release of Swift 4.2 with Xcode 10 (and until the release you can try a 4.2 snapshot).
As an answer to your question:
But shouldn't be this code somehow not be compiled?
Well, at some point your code snippet worked without any issue (because -as you mentioned- the class A init doesn't actually throws), so it could be compiled without any problem. To make it more clear, consider it as a similar case to the following one:
let myString: String? = nil
print(myString!) // crashes!
it will get compiled just fine! although we all know that it crashes when evaluating myString!, i,e we do know it causes a run-time crash, but that doesn't mean that the compiler should prevent it because it could be valid at some point (for instance if we declare it as let myString: String? = "Hello"); Similarly to your case, it could be valid at some point -as mentioned above-.
Usually, for such cases we -as developers- are the responsible to handle it based on what's the desired behavior(s).
Referring to this case, we might need to ask:
"How can we implement the instance lazy variable to catch an error (with a do-catch block)?"
Actually, this code won't compile:
class B {
lazy var instance:A = {
do {
let myA = try A()
return myA
} catch {
print(error)
}
}()
}
complaining that:
Missing return in a closure expected to return 'A'
because obviously reaching the catch block means that there is nothing to be returned. Also, as you mentioned even if you implemented it as
lazy var instance = A()
you will not get a compile-time error, however trying to use it with an actual throwing should leads to run time error:
let myB = B()
print(myB.instance) // crash!
What I would suggest for resolving this issue is to declare instance as lazy optional variable:
class B {
lazy var instance:A? = {
do {
let myA = try A()
return myA
} catch {
print(error)
}
return nil
}()
}
At this point, if we assume that A initializer always throws, trying to access it:
let myB = B()
print(myB.instance)
should log:
caught error
nil
without causing any crash. Otherwise, it should works fine, for instance:
let myB = B()
myB.instance?.doSomething() // works fine
Ok I have a protocol called Environment
protocol Environment {
var rootURL: String {get}
}
Then two structs:
struct Production: Environment {
var rootURL = "www.api.mybackend.com/v1"
}
struct Development: Environment {
var rootURL = "www.api.mydevelopmentbackend.com/v1"
}
A settings object with a function that retrieves the environment:
class Settings {
func getEnvironment<T>() -> T where T: Environment {
let environmentRaw = self.retreiveEnvironmentFromLocalStore()
switch environmentRaw {
case 0:
return Development() as! T
case 1:
return Production() as! T
default:
return Development() as! T
}
}
func retreiveEnvironmentFromLocalStore() -> Int {
//Realm, SQLLite, Core Date, I don't really care for this example.
//Let's just say it defaults to returning 1
}
}
I really want to keep moving in a Protocol Oriented Programming direction but now when I call this function on a settings object and try to use the rootURL property the compiler complains it can't figure out the type. So, to better my understanding and to maybe find a solution:
1) Why does it care about the type if I am accessing a property defined by a protocol that at the very least it knows the returning type conforms to?
2) Structs don't have inheritance. Should I define a base class and forget about generics?
3) Can I make my getEnvironment function better? I don't like force casting, it seems like a code smell.
4) Am I even using generics correctly here?
EDIT 1:
To be clear, I want one function that returns a struct that I know will have this property.
Am I even using generics correctly here?
No, I don't think so. You are saying that getEnvironment will return T which can be any type that the client code specifies, as long as it implements Environment. However, the implementation of the method doesn't do this. It will only return two kinds of Environments, and which type it returns is not determined by the client code. The type returned depends on what retreiveEnvironmentFromLocalStore returns. Hence, generics is not suitable in this case.
Since the type of environment it returns is decided by the implementation of the method, instead of the client code, you should make use of polymorphism here - make it return an Environment instead:
func getEnvironment() -> Environment {
let environmentRaw = self.retreiveEnvironmentFromLocalStore()
switch environmentRaw {
case 0:
return Development()
case 1:
return Production()
default:
return Development()
}
}
I really want to keep moving in a Protocol Oriented Programming direction
I suggest instead you try to move in a clear, understandable code direction, regardless of what the trendy orientation is.
Here's your function declaration:
func getEnvironment() -> T where T: Environment
This says that getEnvironment() will return an object of some type T, where T is deduced at compile time based on the code that calls getEnvironment().
What types could T be? It could be either Production or Development. For example, you could write:
let e: Production = Settings().getEnvironment()
This lets the compiler deduce that getEnvironment() returns a Production (which is an Environment) at this call site.
But there's a problem: getEnvironment() might try to return a Development anyway, based on the random number generator inside retreiveEnvironmentFromLocalStore. Then you'll get a crash at run time when it fails to cast Development to Production.
Why do you think getEnvironment() needs to be generic at all? Based on the code in your question, it shouldn't be.
import Foundation
protocol Environment {
var rootURL: String {get}
}
struct Production: Environment {
var rootURL = "www.api.mybackend.com/v1"
}
struct Development: Environment {
var rootURL = "www.api.mydevelopmentbackend.com/v1"
}
class Settings {
func getEnvironment() -> Environment {
let environmentRaw = self.retreiveEnvironmentFromLocalStore()
switch environmentRaw {
case 1: return Production()
default: return Development()
}
}
func retreiveEnvironmentFromLocalStore() -> Int {
return Int(arc4random())
}
}
let settings = Settings()
let e = settings.getEnvironment()
Style note: the Swift API Design Guidelines advise us to
Name functions and methods according to their side-effects
Those without side-effects should read as noun phrases, e.g. x.distance(to: y), i.successor().
Unless the methods in Settings have important side effects, better names would be environment() and rawEnvironmentFromLocalStore().
There is a protocol Printable and a struct Printer from a 3rd Party.
protocol Printable {}
struct Printer {
static func print<T>(object: T) -> String {
return "T"
}
static func print<T: Printable>(object: T) -> String {
return "Printable"
}
}
Now i am making a generic
struct Generic<T> {
var args: T
func display() {
print(Printer.print(args))
}
}
and two structs
struct Obj {}
struct PrintableObj: Printable {}
var obj = Generic(args: Obj())
var printableObj = Generic(args: PrintableObj())
When i call the display functions on both of them.
obj.display()
displays T
printableObj.display()
displays T but i want it to print "Printable"
One solution i can think of is having two different generics
struct Generic<T>
struct PrintableGeneric<T: Printable>
Is there any other solution without changing the Printable protocol and Printer struct.
static func print<T>(object: T) -> String {
if object is Printable {
return "Printable"
} else {
return "T"
}
}
Yes. But the answer is a bit weird. The first part makes a decent amount of sense; the second part is just totally weird. Let's walk through it.
struct Generic<T> {
var args: T
func display() {
print(Printer.print(args))
}
}
The correct overload to choose for print is decided at compile time, not runtime. This is the thing that confuses people the most. They want to treat Swift like JavaScript where everything is dynamic. Swift likes to be static because then it can make sure your types are right and it can do lots of optimizations (and Swift loves to do compiler optimizations). So, compile time, what type is args? Well, it's T. Is T known to be Printable? No it is not. So it uses the non-Printable version.
But when Swift specializes Generic using PrintableObj, doesn't it know at that point that it's Printable? Couldn't the compiler create a different version of display at that point? Yes, if we knew at compile time every caller that would ever exist of this function, and that none of them would ever be extended to be Printable (which could happen in a completely different module). It's hard to solve this without creating lots of weird corner cases (where internal things behave differently than public things for instance), and without forcing Swift to proactively generate every possible version of display that might be required by some future caller. Swift may improve in time, but this is a hard problem I think. (Swift already suffers some performance reductions so that public generics can be specialized without access to the original source code. This would make that problem even more complicated.)
OK, so we get that. T isn't Printable. But what if we had a type that was unambiguously Printable that we knew at compile time and lived inside this function? Would it work then?
func display() {
if let p = args as? Printable {
print(Printer.print(p))
} else {
print(Printer.print(args))
}
}
Oh so close... but not quite. This almost works. The if-let actually does exactly what you want it to do. p gets assigned. It's Printable. But it still calls the non-Printable function. ?!?!?!?!
This is a place I personally think that Swift is just currently broken and have high hopes it will be fixed. It might even be a bug. The problem is that Printable itself does not conform to Printable. Yeah, I don't get it either, but there you go. So we need to make something that does conform to Printable in order to get the right overload. As usual, type erasers to the rescue.
struct AnyPrintable: Printable {
let value: Printable
}
struct Generic<T> {
var args: T
func display() {
if let p = args as? Printable {
print(Printer.print(AnyPrintable(value: p)))
} else {
print(Printer.print(args))
}
}
}
And this will print the way you wanted. (On the assumption that Printable requires some methods, you'd just add those methods to the AnyPrintable type eraser.)
Of course the right answer is not to use generic overloads this way in Printer. It's just way too confusing and fragile. It looks so nice, but it blows up all the time.
To my mind, the only option you have - is to use if-else with type casting in "print()" function
static func print<T>(object: T) -> String {
if let _ = object as? Printable {
return "Printable"
}
return "T"
}
or non-generic variant
static func print(object: Any) -> String {
if let _ = object as? Printable {
return "Printable"
}
return "T"
}
For Swift fun, I thought I'd build out some alternate reified APIs to GCD. So I threw this in a Playground:
import Foundation
typealias DispatchQueue = dispatch_queue_t
extension DispatchQueue {
static var main:DispatchQueue {
return dispatch_get_main_queue()
}
}
let main = DispatchQueue.main
But this yields an error in the last line:
Static member 'main' cannot be used on instance of type 'DispatchQueue.Protocol' (aka 'OS_dispatch_queue.Protocol')
I'm not sure what this is telling me. I mean, I read it. But I don't see the real problem. I looked at how Double has type vars for things like NaN, and I'm not sure why I can't extend another type with a similar sort of accessor.
(I did try an alternate without the typealias, no difference)
UPDATE: #Kametrixom's answer didn't help right away, but it contributed probably in the end. Here's what I had to do for the light bulb to go on.
class Foo {
static var Bar:Int {
return 42
}
}
Foo.Bar --> 42
Ok, that worked, now a struct.
struct Yik {
static var Yak:Int {
return 13
}
}
Yik.Yak --> 13
That too worked. Now a protocol with an extended default implementation:
protocol Humble { }
extension Humble {
static var Pie:Int {
return 23
}
}
Humble.Pie --> DOES NOT WORK
BUT, extend either the class or the struct with the protocol:
extension Foo: Humble { }
Foo.Pie --> 23
And that works. The mistake I was making (I think?) was in supposing that there was a first class instance of the Humble type running around with that behavior attached to it, which I could invoke, ala composition style. Rather, it's just a template of behavior to be added on to the struct/class types.
I have changed the title of the question. And the answer is No.
If you go to the definition of dispatch_queue_t, you'll find that it's a protocol:
public typealias dispatch_queue_t = OS_dispatch_queue
public protocol OS_dispatch_queue : OS_dispatch_object {}
That means that you aren't actually extending the protocol itself, but rather the types that conform to it. This means to get it to work, you need to get an instance of the protocol of somewhere, get the dynamicType of it and then you can call main:
let DispatchQueueT = (dispatch_queue_create("", DISPATCH_QUEUE_SERIAL) as dispatch_queue_t).dynamicType
DispatchQueueT.main
If I enter the following code in a REPL or Playground or main project, it just hangs when it attempts to create the empty list.
import Cocoa
public final class Box<T> {
private let _value : () -> T
public init(_ value : T) {
self._value = { value }
}
public var value: T {
return _value()
}
}
public enum List<U> {
case Empty
case Cons(U, Box<List<U>>)
}
var l = List<Int>.Empty;
I know this is a popular technique used to get around the fact that Swift doesn't let enums be truly recursive without some indirection (served by the Box class in this example).
I mean it's done here in this project, so I assume this works for some people.
I uninstalled and reinstalled XCode thinking somehow I had some "bad bits" left over from previous beta versions. Anyone else have this issue?
UPDATE 11/17/2015: Of course this question and answer are now obsolete. Please see how to define Recursive Enumerations here: Swift Programming Language - Enumerations
Was working with someone on this and they resolved it.
https://github.com/typelift/swiftz/issues/114
https://github.com/typelift/swiftz/pull/120
The answer is to box the first parameter of Cons as well (you can use an autoclosure) like this Cons(#autoclosure () -> U, Box<List<U>>) and that will fix it. A rdar was filed.