Getters \ Setters for Dummies

What is the correct way to use getters/setters

This works well, does what I need, but I do then have the problem of
two empty IBActions:

You don't need these empty @IBActions. They aren't doing anything for you. The segues are wired from the buttons in the Storyboard, so you don't need the @IBActions. If you delete the code, you also need to remove the connection from the Storyboard or your app will crash when it tries to call the removed @IBActions. To remove, control-click on the buttons in the Storyboard, and then click on the little x next to Touch Up Inside to remove the connection. Then you can delete @IBAction in your code.

if I remove them I have no way to differentiate between which segue
should be used

Not true. You have two different segues wired from two different buttons. The segue's identifiers are how you differentiate between the two segues.

I tried doing: myClass: ViewControllerTwo! = ViewControllerTwo();

When using segues, the segue creates the destination viewController for you.
This doesn't work because you are creating an entirely new ViewControllerTwo here. You are passing the values to this new instance, but this isn't the ViewControllerTwo that the Storyboard segue created for you.

When using segues, you should pass the data in prepare(for:sender:), just like you showed above. Get the destination ViewController and fill in the data you want to pass.

And now for the question you didn't ask:

How could I have done this using the @IBActions to trigger the
segue?

  1. Remove the segues that are wired from your buttons.

  2. Wire the segue from viewController1 to viewController2. Click on the segue arrow in the Storyboard and assign the identifier slideShow.

  3. Assign unique tags to your two buttons. You can set this in Interface Builder. Give the first button tag 1, and the second button tag 2.

  4. Your buttons can share the same @IBAction:

    @IBAction func goToSlideShow(button: UIButton) {
    self.performSegue(withIdentifier: "slideShow", sender: button)
    }
  5. In prepare(for:sender:):

    override func prepare(for segue: UIStoryboardSegue, sender: Any?)
    {
    let passedPic = segue.destination as! ViewControllerTwo

    if let button = sender as? UIButton {
    if button.tag == 1 {
    passedPic.picsChosen = sLS1
    } else if button.tag == 2 {
    passedPic.picsChosen = sLS2
    }
    }
    }

Getters/setters in Java

Nope. AS3 getters and setters are an ECMAScript thing. In Java, you're stuck with the getVal() and setVal() style functions--there isn't any syntactic sugar to make things easy for you.

I think Eclipse can help auto-generating those types of things though...

Is there any point to use getters/setters for an object?

Consider this class.

class Test {
constructor(val) {
this._foo = val;
}

set foo(val) {
throw new Error("It's not possible to change the foo property!")
}

set boo(val) {
console.log("setting _boo")
this._boo = val;
}

get foo() {
console.log("getting _foo");
return this._foo;
}
}

try {
let test = new Test('foooooo');
test.boo = "booooo";
console.log(`foo: ${test.foo}`);
test.foo = "bar";
} catch (e) {
console.log(e);
}

Getters and setters in pure C?

First of all, don't listen to anyone saying "there is no object-orientation in language x" because they have truly not understood that OO is a program design method, completely apart from language syntax.

Some languages have elegant ways to implement OO, some have not. Yet it is possible to write an object-oriented program in any language, for example in C. Similarly, your program will not automagically get a proper OO design just because you wrote it in Java, or because you used certain language keywords.

The way you implement private encapsulation in C is a bit more crude than in languages with OO support, but it does like this:

// module.h

void set_x (int n);
int get_x (void);

// module.c

static int x; // private variable

void set_x (int n)
{
x = n;
}

int get_x (void)
{
return x;
}

// main.c

#include "module.h"

int main (void)
{
set_x(5);
printf("%d", get_x());
}

Can call it "class" or "ADT" or "code module" as you prefer.

This is how every reasonable C program out there is written. And has been written for the past 30-40 years or so, as long as program design has existed. If you say there are no setters/getters in a C program, then that is because you have no experience of using C.

Can I make my own getters and setters and should I?

I've written an article for exactly this. I'll paste it here.


Stop writing getters and setters in Swift

I see this time and time again, and it's about time I write an article in one place to consolidate all my thoughts. If you find yourself writing code that looks like this, listen up:

public class C {
private var _i: Int = 0
public var i: Int {
get {
return self._i
}
set {
self._i = newValue
}
}
}

This pattern* is completely pointless in Swift, and I'll explain why, but firstly we need to take a short detour through Java land. Why Java? Because most of the people I run into who write Swift like this have some sort of Java background, either

  1. because it was taught in their computer sceince courses, or
  2. because they're coming over to iOS development, from Android

What's the point of getters and setters?

Suppose we have the following class in Java:

public class WeatherReport {
public String cityName;
public double temperatureF;

public WeatherReport(String cityName, double temperatureF) {
this.cityName = cityName;
this.temperatureF = temperatureF;
}
}

If you showed this class to any CS prof, they're surely going to bark at you for breaking encapsulation. But what does that really mean? Well, imagine how a class like this would be used. Someone would write some code that looks something like this:

WeatherReport weatherReport = weatherAPI.fetchWeatherReport();
weatherDisplayUI.updateTemperatureF(weatherReport.temperatureF);

Now suppose you wanted to upgrade your class to store data in a more sensible temperature unit (beating the imperial system dead horse, am I funny yet?) like Celcius or Kelvin. What happens when you update your class to look like this:

public class WeatherReport {
public String cityName;
public double temperatureC;

public WeatherReport(String cityName, double temperatureC) {
this.cityName = cityName;
this.temperatureC = temperatureC;
}
}

You've changed the implementation details of your WeatherReport class, but you've also made an API breaking change. Because temperatureF was public, it was part of this class' API. Now that you've removed it, you're going to cause compilation errors in every consumer that depended on the exitense of the temperatureF instance variable.

Even worse, you've changed the semantics of the second double argument of your constructor, which won't cause compilation errors, but behavioural errors at runtime (as people's old Farenheit based values are attemped to be used as if they were celcius values). However, that's not an issue I'll be discussing in this article.

The issue here is that consumers of this class will be strongly coupled to the implementation details of your class. To fix this, you introduce a layer of seperation between your implementation details and your interface. Suppose the Farenheit version of our class was implemented like so:

public class WeatherReport {
private String cityName;
private double temperatureF;

public WeatherReport(String cityName, double temperatureF) {
this.cityName = cityName;
this.temperatureF = temperatureF;
}

public String getCityName() {
return this.cityName;
}

public void setCityName(String cityName) {
this.cityName = cityName;
}

public double getTemperatureF() {
return this.temperatureF;
}

public void setTemperatureF(double temperatureF) {
this.temperatureF = temperatureF;
}
}

The getters and setters are really basic methods that access or update our instance variables. Notice how this time, our instance variables are private, and only our getters and setters are public. A consumer would use this code, as so:

WeatherReport weatherReport = weatherAPI.fetchWeatherReport();
weatherDisplayUI.updateTemperatureF(weatherReport.getTemperatureF());

This time, when we make the upgrade to celcius, we have the freedom to change our instance variables, and tweak our class to keep it backwards compatible:

public class WeatherReport {
private String cityName;
private double temperatureC;

public WeatherReport(String cityName, double getTemperatureC) {
this.cityName = cityName;
this.temperatureC = temperatureC;
}

public String getCityName() {
return this.cityName;
}

public void setCityName(String cityName) {
this.cityName = cityName;
}

// Updated getTemperatureF is no longer a simple getter, but instead a function that derives
// its Farenheit value from the Celcius value that actuallyed stored in an instance variable.
public double getTemperatureF() {
return this.getTemperatureC() * 9.0/5.0 + 32.0;
}

// Updated getTemperatureF is no longer a simple setter, but instead a function
// that updates the celcius value stored in the instance variable by first converting from Farenheit
public void setTemperatureF(double temperatureF) {
this.setTemperatureC((temperatureF - 32.0) * 5.0/9.0);
}

// Mew getter, for the new temperatureC instance variable
public double getTemperatureC() {
return this.temperatureC;
}

// New setter, for the new temperatureC instance variable
public void setTemperatureC(double temperatureC) {
this.temperatureC = temperatureC;
}
}

We've added new getters and setters so that new consumers can deal with temperatures in Celcius. But importantly, we've re-implemented the methods that used to be getters and setters for temperatureF (which no longer exists), to do the appropraite conversions and forward on to the Celcius getters and setters. Because these methods still exist, and behave identically as before, we've successfully made out implementation change (storing F to storing C), without breaking our API. Consumers of this API won't notice a difference.

So why doesn't this translate into Swift?

It does. But simply put, it's already done for you. You see, stored properties in Swift are not instance variables. In fact, Swift does not provide a way for you to create or directly access instance variables.

To understand this, we need to have a fuller understanding of what properties are. There are two types, stored and computed, and neither of them are "instance variables".

  • Stored properties: Are a combination of a comiler-synthesized instance variable (which you never get to see, hear, touch, taste, or smell), and the getter and setter that you use to interact with them.
  • Computed proepties: Are just a getter and setter, without any instance variable to act as backing storage. Really, they just behave as functions with type () -> T, and (T) -> Void, but have a pleasant dot notation syntax:

    print(weatherReport.temperatureC)
    weatherReport.temperatureC = 100

    rather than a function calling synax:

    print(weatherReport.getTemperatureC())
    weatherReport.setTemperatureC(100)

So in fact, when you write:

class C {
var i: Int
}

i is the name of the getter and setter for an instance variable the compiler created for you. Let's call the instance variable $i (which is not an otherwise legal Swift identifier). There is no way to directly access $i. You can only get its value by calling the getter i, or update its value by calling its setter i.

So lets see how the WeatherReport migration problem looks like in Swift. Our initial type would look like this:

public struct WeatherReport {
public let cityName: String
public let temperatureF: Double
}

Consumers would access the temperature with weatherReport.temperatureF. Now, this looks like a direct access of an isntance variable, but remember, that's simply not possible in Swift. Instead, this code calls the compiler-syntehsized getter temperatureF, which is what accesses the instance variable $temperatureF.

Now let's do our upgrade to Celcius. We will first update our stored property:

public struct WeatherReport {
public let cityName: String
public let temperatureC: Double
}

This has broken our API. New consumers can use temperatureC, but old consumers who depended on temperatureF will no longer work. To support them, we simply add in a new computed property, that does the conversions between Celcius and Fahenheit:

public struct WeatherReport {
public let cityName: String

public let temperatureC: Double
public var temperatureF: Double {
get { return temperatureC * 9/5 + 32 }
set { temperatureC = (newValue - 32) * 5/9 }
}
}

Because our WeatherReport type still has a getter called temperatureF, consumers will behave just as before. They can't tell whether a property that they access is a getter for a stored property, or a computed property that derives its value in some other way.

So lets look at the original "bad" code. What's so bad about it?

public class C {
private var _i: Int = 0
public var i: Int {
get {
return self._i
}
set {
self._i = newValue
}
}
}

When you call c.i, the following happens:

  1. You access the getter i.
  2. The getter i accesses self._i, which is yet another getter
  3. The getter _i access the "hidden" instance variable $i

And it's similar for the setter. You have two layers of "getterness". See what that would look like in Java:

public class C {
private int i;

public C(int i) {
this.i = i;
}

public int getI1() {
return this.i;
}

public void setI1(int i) {
this.i = i;
}

public int getI2() {
return this.getI1();
}

public void setI2(int i) {
this.setI1(i);
}
}

It's silly!

But what if I want a private setter?

Rather than writing this:

public class C {
private var _i: Int = 0

public var i: Int {
get {
return self._i
}
}
}

You can use this nifty syntax, to specify a seperate access level for the setter:

public class C {
public private(set) var i: Int = 0
}

Now isn't that clean?

Why use getters and setters/accessors?

There are actually many good reasons to consider using accessors rather than directly exposing fields of a class - beyond just the argument of encapsulation and making future changes easier.

Here are the some of the reasons I am aware of:

  • Encapsulation of behavior associated with getting or setting the property - this allows additional functionality (like validation) to be added more easily later.
  • Hiding the internal representation of the property while exposing a property using an alternative representation.
  • Insulating your public interface from change - allowing the public interface to remain constant while the implementation changes without affecting existing consumers.
  • Controlling the lifetime and memory management (disposal) semantics of the property - particularly important in non-managed memory environments (like C++ or Objective-C).
  • Providing a debugging interception point for when a property changes at runtime - debugging when and where a property changed to a particular value can be quite difficult without this in some languages.
  • Improved interoperability with libraries that are designed to operate against property getter/setters - Mocking, Serialization, and WPF come to mind.
  • Allowing inheritors to change the semantics of how the property behaves and is exposed by overriding the getter/setter methods.
  • Allowing the getter/setter to be passed around as lambda expressions rather than values.
  • Getters and setters can allow different access levels - for example the get may be public, but the set could be protected.

Getters and Setters vs Oject key value pair

I think you might choose to use get and setters as a interface to handle your data, in some cases it can help you to organize your code and don't mess it arround.

At many cases i stick with getters and setters, which makes my code secure, as only that keys (the ones specified at your setter) will be updated. Also, you can implement the visibility on it, so only inside the class could access some methods, it will vary with your needs.

Im trying to understand Getters and Setters in the ruby programming language

Understanding attr_accesor, attr_reader and attr_writer

These are Ruby's getters and setters shortcut. It works like C# properties, that injects the get_Prop (getter) and set_Prop (setter) methods.

  • attr_accessor: injects prop (getter) and prop= (setter) methods.
  • attr_reader: it's a shortcut for read-only properties. Injects prop method. The prop value can only be changed inside the class, manipulating the instance variable @prop.
  • attr_writer: it's a shortcut for write-only properties. Injects prop= method.

Ruby doesn't have methods called get_prop (getter) and set_prop (setter), instead, they're called prop (getter) and prop= (setter).

That being said, you can infer that

class Person
attr_accessor :name, :age
end

is the short version for

class Person
# getter
def name
return @name
end

# setter
def name=(value)
@name = value
end
end

You don't need to call return, Ruby methods returns the last executed statement.

If you are using Ruby on Rails gem, you can build model objects using new and passing properties values as arguments, just like:

p = Person.new(name: 'Vinicius', age: 18)
p.name
=> 'Vinicius'

That's possible because Rails injects something like this initialize method to ActiveRecord::Base and classes that includes ActiveModel::Model:

def initialize(params)
params.each do |key, value|
instance_variable_set("@#{key}", value)
end
end


Related Topics



Leave a reply



Submit