Properties (getters and setters) in Ceylon - properties

How do I define a property in Ceylon? I know I can write getName and setName functions to get and set a backing variable:
class Circle(shared variable Float radius) {
shared Float getArea() {
return pi * radius ^ 2;
}
shared void setArea(Float area) {
radius = sqrt(area / pi);
}
}
value circle = Circle(4.0);
circle.setArea(10.0);
print(circle.getArea());
But I would like to be able to provide attribute-like access to the property:
value circle = Circle(4.0);
circle.area = 10.0;
print(circle.area);
How do I do this in Ceylon?

Getters are declared like defining a function with no parameter list. The getter body then behaves like a normal function and must return the calculated value of the property.
variable String local_var = "Hello world!";
// Getter
String name1 {
return local_var;
}
// Also getter, using functional syntax for body
String name2 => local_var;
Setters are declared using the assign keyword. The setter body then behaves like a void function, performing whatever mutation of the local environment is appropriate and must not return a value. The incoming value being assigned can be referred to in the body via the name of the property.
// Setter
assign name1 {
local_var = name1; // name1 here is value being assigned
}
// Also setter, using modified functional syntax
assign name2 => local_var = name2;
Unlike most programming languages, properties can be top level members of the package, not just members of a class:
class Circle(shared variable Float radius) {
// Class-level getter
shared Float area {
return pi * radius ^ 2;
}
// Class-level setter
assign area {
radius = sqrt(area / pi);
}
}
Circle window = Circle(1.0);
// Top-level getter
Circle outer_window => Circle(window.radius * 2);
// Top-level setter
assign outer_window => window.radius = outer_window.radius / 2;

Additional comment: on the Java backend, Ceylon getters and setters compile to Java getters and setters (using the standard getFoo/setFoo names, or isFoo for Boolean properties). Defining regular functions named like getters and setters, like getArea and setArea in the question, is strongly discouraged, and if you do define them, their backing functions will actually be called something different (e. g. $getArea) to avoid collision with the getters and setters generated automatically by the compiler.

Related

Class field with different argument types (setter overloading)

I have a class with a field of type long and I would like to pass either an Int or a Long value.
So I thought I can make a second setter with the same name, but different argument.
Kotlin does not complain and I can even call both setters from Java (same name, one automatically created with long from Kotlin). In Java I just call setMyNumber(long or int) value and the compiler will assign the correct method.
But why can't I do myNumber = 4 in Kotlin, why does it not call the other setter?
Is there a different way I can achieve this functionality, but still keep the property notation (yes I know I can write to setter methods, but then I have to call them with a method call rather just assigning a value)?
class MyClass {
var myNumber: Long = 0L // internal setMyNumber(value: Long)
fun setMyNumber(newNumber: Int) {
myNumber = newNumber.toLong()
}
}
As of writing, what you're trying to do is not supported. (See: Allow setters overloading for properties)
A workaround would be using the Superclass for all platform classes representing numeric values:
class MyClass {
var myNumber: Number = 0L
set (value) { field = value.toLong() }
}
val myClass = MyClass()
val anInt: Int = 1
val aLong: Long = 1L
myClass.myNumber = anInt
myClass.myNumber = aLong
Try it online!

What are the implementation of default accessors in Kotlin

I have a class like this
class Square(var width: Int, var height: Int) {
var color : String = "red"
}
As my understanding Kotlin's compiler will consider width, height and color are properties of class Square and therefore it will generate setter and getter for these properties automatically.
With property color, i guess the getter and setter of it should be liked this
var color : String = "red"
get() = field
set(value) { field = value}
But how about the default setter and getter of the width and height properties. These properties don't have initialization values so they can't have "field" identifier in the getter and setter. Does anyone know the answer?
Properties placed in the header of a class declaration are a convenience if you need to store simple properties in a class, and you want to initialize them through constructor arguments with the same names. If you use these, you give up the ability to give them custom setters and getters - this can only be done for properties in the body of the class.
Otherwise, the default implementation of their getters (and setters for vars) are the same as for properties in the class body. They just return (and set) the value of the backing field.
Edit, following up on the comments above: this also means that the properties in the constructor always have to be initialized, they can't be computed properties, since you can't give them getters and setters that wouldn't use their backing field.

How to declare a property as a function in Swift?

Here is my code:
import Cocoa
class VC1: NSViewController {
let aFunctionVar ()->Void
}
The compiler however tells me: "Class VC1 has no initializers"
According to the swift example in Apple Swift iBook, they did their examplle like so:
var mathFunction: (Int, Int) -> Int = addTwoInts
But in my case, I'm trying to create a property variable. It is not yet known what the variable will be, so i can't set it there. Any help?
Edit - I already know how to make variables optional and lazy when it comes to simple String/Array/Dictionary types etc. But this is a function type property variable. It is meant to hold a function of type ()->Void. Any help on how this can be done?
In objectiveC this can be done by making a block property like this:
#property (nonatomic, copy) void (^aFunctionVar)();
Declare projectLaunchData as an optional var:
import Cocoa
class VC1: NSViewController {
var projectLaunchData: (()->Void)?
}
Then you can assign a value later:
func test() {
print("this works")
}
let myVC = VC1()
// assign the function
myVC.projectLaunchData = test
// Call the function using optional chaining. This will safely do nothing
// if projectLaunchData is nil, and call the function if it has been assigned.
// If the function returns a value, it will then be optional because it was
// called with the optional chaining syntax.
myVC.projectLaunchData?()
If the value will be known after the object is setup, you can use a lazy variable:
class LazyTester {
lazy var someLazyString: String = {
return "So sleepy"
}()
}
var myLazyTester = LazyTester()
myLazyTester.someLazyString
The compiler is giving you that error because you are defining a mandatory stored variable, projectLaunchData, but not giving it a value. If you know the variables value at init time, you can set it at init time.

How do I express this setter pattern in Swift?

We usually do things lik
- (void)setFoo:(Foo *)foo
{
_foo = foo;
// other computation
}
Getter and Setters give me warning that I cant set my own property. I am guessing it needs a computed property. What would be the best way to translate this idiom in Swift?
If you're doing computation tightly integrated with setting the internal storage of foo, especially if setting the storage is conditional on such computation, the computed-property/stored-property pair #matt suggests is probably the solution you need.
Otherwise—if you need to need to do work unconditionally in response to the setting of a property—what you're looking for is Swift's property observers feature.
var foo: Foo {
willSet(newFoo) {
// do work that happens before the internal storage changes
// use 'newFoo' to reference the value to be stored
}
didSet {
// do work that happens after the internal storage changes
// use 'oldValue' to reference the value from before the change
}
}
You can "shadow" a public computed variable with a stored private variable, like this:
private var _foo : Foo!
var foo : Foo {
get {
return _foo
}
set (newfoo) {
_foo = newfoo
}
}
That is the analogy to what Objective-C #synthesize does. But you should also ask yourself whether you really need this. In most cases, you don't.

Error in Swift class: Property not initialized at super.init call

I have two classes, Shape and Square
class Shape {
var numberOfSides = 0
var name: String
init(name:String) {
self.name = name
}
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
class Square: Shape {
var sideLength: Double
init(sideLength:Double, name:String) {
super.init(name:name) // Error here
self.sideLength = sideLength
numberOfSides = 4
}
func area () -> Double {
return sideLength * sideLength
}
}
With the implementation above I get the error:
property 'self.sideLength' not initialized at super.init call
super.init(name:name)
Why do I have to set self.sideLength before calling super.init?
Quote from The Swift Programming Language, which answers your question:
“Swift’s compiler performs four helpful safety-checks to make sure
that two-phase initialization is completed without error:”
Safety check 1 “A designated initializer must ensure that all of the
“properties introduced by its class are initialized before it
delegates up to a superclass initializer.”
Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks.
https://itunes.apple.com/us/book/swift-programming-language/id881256329?mt=11
Swift has a very clear, specific sequence of operations that are done in initializers. Let's start with some basic examples and work our way up to a general case.
Let's take an object A. We'll define it as follows.
class A {
var x: Int
init(x: Int) {
self.x = x
}
}
Notice that A does not have a superclass, so it cannot call a super.init() function as it does not exist.
OK, so now let's subclass A with a new class named B.
class B: A {
var y: Int
init(x: Int, y: Int) {
self.y = y
super.init(x: x)
}
}
This is a departure from Objective-C where [super init] would typically be called first before anything else. Not so in Swift. You are responsible for ensuring that your instance variables are in a consistent state before you do anything else, including calling methods (which includes your superclass' initializer).
From the docs
Safety check 1
A designated initializer must ensure that all of the properties
introduced by its class are initialized before it delegates up to a
superclass initializer.
Why do we need a safety check like this?
To answer this lets go though the initialization process in swift.
Two-Phase Initialization
Class initialization in Swift is a two-phase process. In the first
phase, each stored property is assigned an initial value by the class
that introduced it. Once the initial state for every stored property
has been determined, the second phase begins, and each class is given
the opportunity to customize its stored properties further before the
new instance is considered ready for use.
The use of a two-phase initialization process makes initialization
safe, while still giving complete flexibility to each class in a class
hierarchy. Two-phase initialization prevents property values from
being accessed before they are initialized, and prevents property
values from being set to a different value by another initializer
unexpectedly.
So, to make sure the two step initialization process is done as defined above, there are four safety checks, one of them is,
Safety check 1
A designated initializer must ensure that all of the properties
introduced by its class are initialized before it delegates up to a
superclass initializer.
Now, the two phase initialization never talks about order, but this safety check, introduces super.init to be ordered, after the initialization of all the properties.
Safety check 1 might seem irrelevant as,
Two-phase initialization prevents property values from being accessed before they are initialized can be satisfied, without this safety check 1.
Like in this sample
class Shape {
var name: String
var sides : Int
init(sides:Int, named: String) {
self.sides = sides
self.name = named
}
}
class Triangle: Shape {
var hypotenuse: Int
init(hypotenuse:Int) {
super.init(sides: 3, named: "Triangle")
self.hypotenuse = hypotenuse
}
}
Triangle.init has initialized, every property before being used. So Safety check 1 seems irrelevant,
But then there could be another scenario, a little bit complex,
class Shape {
var name: String
var sides : Int
init(sides:Int, named: String) {
self.sides = sides
self.name = named
printShapeDescription()
}
func printShapeDescription() {
print("Shape Name :\(self.name)")
print("Sides :\(self.sides)")
}
}
class Triangle: Shape {
var hypotenuse: Int
init(hypotenuse:Int) {
self.hypotenuse = hypotenuse
super.init(sides: 3, named: "Triangle")
}
override func printShapeDescription() {
super.printShapeDescription()
print("Hypotenuse :\(self.hypotenuse)")
}
}
let triangle = Triangle(hypotenuse: 12)
Output :
Shape Name :Triangle
Sides :3
Hypotenuse :12
Here if we had called the super.init before setting the hypotenuse, the super.init call would then have called the printShapeDescription() and since that has been overridden it would first fallback to Triangle class implementation of printShapeDescription(). The printShapeDescription() of Triangle class access the hypotenuse a non optional property that still has not been initialised. And this is not allowed as Two-phase initialization prevents property values from being accessed before they are initialized
So make sure the Two phase initialization is done as defined, there needs to be a specific order of calling super.init, and that is, after initializing all the properties introduced by self class, thus we need a Safety check 1
The "super.init()" should be called after you initialize all your instance variables.
In Apple's "Intermediate Swift" video (you can find it in Apple Developer video resource page https://developer.apple.com/videos/wwdc/2014/), at about 28:40, it is explicit said that all initializers in super class must be called AFTER you initialize your instance variables.
In Objective-C, it was the reverse. In Swift, since all properties need to be initialized before it's used, we need to initialize properties first. This is meant to prevent a call to overrided function from super class's "init()" method, without initializing properties first.
So the implementation of "Square" should be:
class Square: Shape {
var sideLength: Double
init(sideLength:Double, name:String) {
self.sideLength = sideLength
numberOfSides = 4
super.init(name:name) // Correct position for "super.init()"
}
func area () -> Double {
return sideLength * sideLength
}
}
Sorry for ugly formatting.
Just put a question character after declaration and everything will be ok.
A question tells the compiler that the value is optional.
class Square: Shape {
var sideLength: Double? // <=== like this ..
init(sideLength:Double, name:String) {
super.init(name:name) // Error here
self.sideLength = sideLength
numberOfSides = 4
}
func area () -> Double {
return sideLength * sideLength
}
}
Edit1:
There is a better way to skip this error. According to jmaschad's comment there is no reason to use optional in your case cause optionals are not comfortable in use and You always have to check if optional is not nil before accessing it. So all you have to do is to initialize member after declaration:
class Square: Shape {
var sideLength: Double=Double()
init(sideLength:Double, name:String) {
super.init(name:name)
self.sideLength = sideLength
numberOfSides = 4
}
func area () -> Double {
return sideLength * sideLength
}
}
Edit2:
After two minuses got on this answer I found even better way. If you want class member to be initialized in your constructor you must assign initial value to it inside contructor and before super.init() call. Like this:
class Square: Shape {
var sideLength: Double
init(sideLength:Double, name:String) {
self.sideLength = sideLength // <= before super.init call..
super.init(name:name)
numberOfSides = 4
}
func area () -> Double {
return sideLength * sideLength
}
}
Good luck in learning Swift.
swift enforces you to initialise every member var before it is ever/might ever be used. Since it can't be sure what happens when it is supers turn, it errors out: better safe than sorry
Edward,
You can modify the code in your example like this:
var playerShip:PlayerShip!
var deltaPoint = CGPointZero
init(size: CGSize)
{
super.init(size: size)
playerLayerNode.addChild(playerShip)
}
This is using an implicitly unwrapped optional.
In documentation we can read:
"As with optionals, if you don’t provide an initial value when you
declare an implicitly unwrapped optional variable or property, it’s
value automatically defaults to nil."
Swift will not allow you to initialise super class with out initialising the properties, reverse of Obj C. So you have to initialise all properties before calling "super.init".
Please go to http://blog.scottlogic.com/2014/11/20/swift-initialisation.html.
It gives a nice explanation to your problem.
Add nil to the end of the declaration.
// Must be nil or swift complains
var someProtocol:SomeProtocol? = nil
// Init the view
override init(frame: CGRect)
super.init(frame: frame)
...
This worked for my case, but may not work for yours
its should be this:
init(sideLength:Double, name:String) {
self.sideLength = sideLength
super.init(name:name)
numberOfSides = 4
}
look at this link:
https://swiftgg.gitbook.io/swift/swift-jiao-cheng/14_initialization#two-phase-initialization
You are just initing in the wrong order.
class Shape2 {
var numberOfSides = 0
var name: String
init(name:String) {
self.name = name
}
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
class Square2: Shape2 {
var sideLength: Double
init(sideLength:Double, name:String) {
self.sideLength = sideLength
super.init(name:name) // It should be behind "self.sideLength = sideLength"
numberOfSides = 4
}
func area () -> Double {
return sideLength * sideLength
}
}
#Janos if you make the property optional, you don't have to initialise it in init. –
This worked for me.