How to omit argument name in a struct - swift

Swift beginner here... When passing a value into a struct instance during instantiation, is there a way to omit the argument name? I can't find anything in Swift documentation.
struct Dog {
var _ name: String
}
var buddy = Dog("Buddy")
Obviously this does not work. In functions you can use an underscore before the parameter name to omit it during calling, is this possible in some way with structs?

Properties always have names. What can differ are the keyword labels of the initializer. If you don't specify your own initializer, the compiler will synthesize a default memberwise initializer for you, which will have argument labels that match the member names.
If you wish to change that, you would forego the compiler-provided initializer, and specify your own:
struct Dog {
var name: String
init(_ name: String) {
self.name = name
}
}

Related

Invalid redeclaraciton of property for protocol when base class has optional property of same name

I have a protocol that has a property name: String. I have a base class that has a property of name: String?. When I try to adopt the protocol, I keep getting invalid redeclaration error. How do I redeclare a property of the same name but optional?
protocol Targetable {
var id: String { get }
var name: String { get }
}
You cannot have several properties with the same name, but different types, so you cannot achieve what you are trying to achieve. Even if you changed the type of name of a completely unrelated type (let's say Int), you'd get the same error, this has nothing to do with one of the two declarations being Optional.

In Swift do you not have to use a getter and setter when creating an object type, such as class, that conforms to a protocol requiring so?

protocol UserType {
var name: String { get }
var age: Int { get set }
struct Person: UserType {
var name: String //<- why is this okay?
var age: Int //<- why is this okay? dont we need a getter setter
}
let somePerson = Person(name: "Billy", age: 22)
Why in the above examples, we dont use get constructs or set constructs for age and a get construct for name? Is it because in the protocol when the property is said to "{ get set }" that essentially means it has to be able to be read and has to be able to be changed, which can be done through a declaration in the syntax of a stored property?
Thanks!
protocol UserType {
var name: String { get }
var age: Int { get set }
}
The important thing to understand is that { get } and { get set } are merely notations. They have nothing to do with "getter and setter". They are merely ways of describing to the compiler what the protocol's requirements are. (You could argue that the notation is confusing or misleading, but it's what we've got, so we have to live with it.)
So, basically, all this says is:
An adopter must declare a name String instance property.
An adopter must also declare an age Int instance property and that property must be writable.
That's all it means. Well, you have satisfied those requirements in your adopter (Person). Your code is legal. The end.
One thing to note first: Every property has an implicit getter and setter unless otherwise stated. e.g. a simple var age: Int implicitly has a get and set, and let age: Int implicitly has a get. When you declare a manual getter and setter, you're overriding something, not creating something that didn't otherwise exist.
As for protocols, in explicit terms:
var name: String { get } means the adhering Type must have a property with a signature of name:String that can be read, AKA. get
var age: Int { get set } means the adhering Type must have a property with a signature of age:String that can be read or assigned, AKA get and set
Note that these rules are inclusive not exclusive. The requirements don't care how they are satisfied, and don't disallow anything else.
This means with your given example, a property of let name: String would work because it only requires access, but let age: Int wouldn't work, because it cannot be changed. It also doesn't care about internal details, so using computed properties, private setters, etc. is fine as long as they have the necessary access.

Why do we need to specify init method?

The following block of code runs fine even without specifying the init method. If this is the case, what purpose does the init method serve?
struct Person {
var name: String
var age: Int
init(name: String, age: Int){
self.name = name
self.age = age
}
}
let somePerson = Person(name: "Sam", age: 21)
somePerson.name
somePerson.age
Thank you your feedback.
As pointed out in this doc
Swift initializers
Swift provides a default initializer for any structure or class that
provides default values for all of its properties and does not provide
at least one initializer itself. The default initializer simply
creates a new instance with all of its properties set to their default
values.
Structure types automatically receive a memberwise initializer if they do not
define any of their own custom initializers. Unlike a default
initializer, the structure receives a memberwise initializer even if
it has stored properties that do not have default values.
So if you write one init method, then you MUST write the default initializer yourself, if you want it to exist.
If you only need the default initializer, then you can omit it.
It's the behavior of Struct in swift.
See (Memberwise Initializers for Structure Types) in https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html
"Structure types automatically receive a memberwise initializer if
they do not define any of their own custom initializers. Unlike a
default initializer, the structure receives a memberwise initializer
even if it has stored properties that do not have default values."
If you do not specify any memberwise init method, it will create for you. The init that you declare allow you to do more than just an simple init. For example:
struct Person {
var name: String
var age: Int
init(name: String, age: Int){
self.name = name.uppercaseString()
self.age = age + 22
//and more works ...
}
}
You don't need it (anymore). Memberwise initialization is a new feature of Swift 2.2. The author either wrote this code for an earlier version of Swift or didn't know that it's no longer necessary.

Why do I have to pass arguments to classes in key-value form?

class NamedShape {
var numberOfSides: Int = 0
var name: String
init(name: String) {
self.name = name
}
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides named \(name)"
}
}
I have the following example class. To create a new instance, I do
let shape = NamedShape(name: "Test")
The arguments are captured by the init() function, right? However, if I do this:
let shape = NamedShape("Test")
I get a missing argument label error!
However, if I define a silly function like this:
func printInt(numberIn: Int) {
println(numberIn)
}
I can invoke it just fine using:
printInt(5)
However, if I attempt to invoke it with the arguments formatted in the way I create a class:
printInt(numberIn: 5)
I get an extraneous argument label error!
Help a swift noob understand. Why do I need to label class arguments, but I can't label function arguments? Why are functions and classes different this way? I'm sure there's something I'm missing.
Because initializer functions aren’t called with a function name, the parameter types and names are used to disambiguate among multiple init() functions. Thus, init() function parameters have external names by default.
You can explicitly opt out of default parameter names with an underscore:
init(_ name: String) {
self.name = name
}
init() functions are special cases and all parameters are required to have an external name.
https://developer.apple.com/library/ios/documentation/swift/conceptual/Swift_Programming_Language/Initialization.html#//apple_ref/doc/uid/TP40014097-CH18-XID_306

How can I make the memberwise initialiser public, by default, for structs in Swift?

I have a Swift framework that defines a struct:
public struct CollectionTO {
var index: Order
var title: String
var description: String
}
However, I can't seem to use the implicit memberwise initialiser from another project that imports the library. The error is:
'CollectionTO' cannot be initialised because it has no accessible initialisers
i.e. the default synthesized memberwise initialiser is not public.
var collection1 = CollectionTO(index: 1, title: "New Releases", description: "All the new releases")
I'm having to add my own init method like so:
public struct CollectionTO {
var index: Order
var title: String
var description: String
public init(index: Order, title: String, description: String) {
self.index = index;
self.title = title;
self.description = description;
}
}
... but is there a way to do this without explicitly defining a public init?
Quoting the manual:
"Default Memberwise Initializers for Structure Types
The default memberwise initializer for a structure type is considered private if any of the structure’s stored properties are private. Otherwise, the initializer has an access level of internal.
As with the default initializer above, if you want a public structure type to be initializable with a memberwise initializer when used in another module, you must provide a public memberwise initializer yourself as part of the type’s definition."
Excerpt from "The Swift Programming Language", section "Access Control".
While it is not possible to have the default memberwise initializer at least you can make one quickly with the following steps:
UPDATE: Xcode 11 and later
As mentioned by Brock Batsell on the comments, for Xcode 11 and later all you need to is this:
Right click the class or struct name and choose refactor ->
Generate Memberwise Initializer
Xcode 10 and earlier answer
Make the object a class temporarily instead of a struct
Save
Right click the class name and choose refactor ->
Generate Memberwise Initializer
Change it back to a struct
We now have a ruby gem 💎 to parse a complete swift data model file, line-by-line, and add public access modifiers, public member-wise default initializers, and other things into a separate auto-generated output swift file.
This gem is called swift_republic
Please check out the following documentation for running this gem:
https://github.com/mehul90/swift_republic
Sometimes it's really annoying having an initializer when you don't need one. If you're constantly updating the variables to the object, it becomes bothersome very quickly to update the variables in 3 places (variable declaration, initializer parameter, and initializer implementation).
A workaround I've used for this issue is to have a static variable on the struct to act as (or essentially wrap) the "initializer". For instance:
struct MyStruct {
static var empty = Self()
static func empty(name: String) -> Self {
.init(privateName: name)
}
private var identifier: String = ""
}
Then you can call it similar to how you would an initializer (with autocomplete and everything!):
func someFunction(_ value: MyStruct) { ... }
//someFunction(.init()) -> ERROR, invalid due to `private` variable
someFunction(.empty)
someFunction(.empty(name: "Dan IRL"))
let myObject = MyStruct.empty
let myObject2 = MyStruct.empty(name: "Monty Python")
You have to define public init by yourself, luckily starting from Xcode 14 🥳 there is an automatic initializer completion (source - 60399329)