Using self in a callback passed to super.init - swift

I've got a base class. In this base class I take some callbacks in the init method. In these callbacks I'd like to reference the derived class's self. However, Swift complains that the lambdas reference self before super.init. Of course, I know that in reality, the base class doesn't invoke the callbacks actually inside super.init and even if it did, that's not clearly illegal, since it would not be before super.init.
How can I pass a callback to super.init that references self?

It is not possible to reference self in anyway before you have called the super.init. self can only be referenced when the initialisation is done. You have to look for alternative ways to create your object (factory methods, builder pattern).

I managed to work around this meaningless restriction by refactoring the class somewhat. Instead of simply passing the constructor the data it needs directly, instead there's a getter for the data which just happens to be called exactly once by the superclass constructor. The variable that stores this data, instead of being immutable and proper, now is initialized with nil (i.e. left uninitialized) and then initialized later through the getter and then there's another getter-only computed property.
So now anyone who tries to read the class will be thoroughly confused by the worthless meandering around the point, but it does actually have the desired semantics.

Related

Why can't non-nullable fields be initialized in a constructor body in Dart?

Often times I have an instance field that needs to be initialized in a constructor. For example, it might be needed to be calculated based on other instance fields, hence I can't initialize it inline (where declared) or with a constructor initializer list.
But it either has to be nullable, or declared late, if I need to initialize it in constructor. The rationale behind late keyword is that programmer states "I'll initialize this before using, trust me", when it can not be determined by the compiler that initialization will take place before first usage. BUT: this "programmer guarantee" seems A) terrible and B) unnecessary in case of constructors, because it can be determined by compiler whether the field was initialized in a constructor (and constructor itself is obviously guaranteed to execute before any other instance methods).
Obvious downside to using late fields in such scenarios is that nothing enforces them compile-time to be actually initialized during construction (or anywhere, for that matter). Plus, every time the late field is read, a runtime check is inserted to make sure it has been assigned a value - I don't need that when I initialize in constructors.
Therefore, it seems that, technically it should be possible to have non-nullable non-late fields that are initialized within a constructor body (and if they are not - compiler can throw an error).
So what is the rationale of requiring constructor-initialized fields to be either nullable, or declared as late? Is there a technical reason why this limitation is imposed, or is it just a design oversight by the Dart team?
Dart executes constructor bodies inside-out, from base class to derived class. This allows virtual dispatch to occur in the constructor body. The fact that virtual dispatch can occur in the constructor body means that the compiler cannot statically determine what code will be executed by the constructor body, and therefore it cannot deduce what the constructor body might ultimately initialize.
That the constructor body can execute arbitrary code (including callbacks) that might initialize members or that might depend on initialized members makes it even more complicated.
Furthermore, allowing members to be not initialized when the constructor body runs would be error-prone and a source for confusion. For example, with:
class SomeClass {
int member;
SomeClass() {
updateMember(0);
}
void updateMember(int value) {
print(value); // Oops.
member = value;
}
}
With Dart's current design, all instance methods (and their overrides) can be guaranteed that members are initialized when the method is called. If members were allowed to be uninitialized when the constructor body is executed, that would not longer be true, and all instance methods then would need to consider if they might be invoked from the constructor (or from a base class constructor), possibly indirectly from other method calls, and whether accessed members might not be initialized yet.
(I'll grant that that previous point isn't terribly strong since it currently can still happen that a member is initialized to an object that the constructor body must mutate, but typically instance methods receiving an empty List, Map, etc. is less of a problem than receiving uninitialized members. The above situation also could happen with late members, but that's the baggage that comes with choosing to use late.)
Null-safety disallows the possibility of accessing uninitialized non-late variables, but your proposal would make that possible.
Also, because there is a distinction between initializing members via an initializer list and via a constructor body, people are encouraged to use initializer lists when possible.
The point that you are ignoring here is that when you want to pass a variable to a constructor you will definitely initialize it, otherwise you wouldn't be able to use that widget because you have to pass the variables needed to its constructor. so this late or nullable keywords can be used for the values that you are trying to pass to a widget and not in the widget itself that you are passing them to, but before it.

Swift. Let to override but not to call the method

Is there any way to let the method of the superclass be overrided, but not called directly?
For example: A inherited from B. There is two methods. One is final and must be called, second is overridable but shouldn't be called, only override.
I tried #available and private but that don't fit. I think that it can be reached by delegate, but maybe there is another way?
For example, you can throw an error in your method that will say that this method shouldn't be called and child class should override it. But, of course, it is no compile time restriction, only runtime.
Also it has sense for you to read discussion here: Abstract functions in Swift Language

Why do we need a weakSelf for functions/methods within closures?

Reading my own answer.
I fully understand why we need a weakSelf for members/properties. They could create memory cycles. But properties have a memory location.
Do functions also have memory locations?! I mean isn't a function something just happens on the go? If so is the memory location type any different from a property location?
If I don't refer using self I get this error.
Call to method 'alertFunc' in closure requires explicit 'self.' to
make capture semantics explicit
which is slightly different from:
Reference to property 'window' in closure requires explicit 'self.' to
make capture semantics explicit
My code is as follows:
let another = UIAlertAction(title: "Log", style:UIAlertActionStyle.Default){action in
logAction ()
}
private func logAction () {
print("health")
}
credit to iOS nerds I know from a meetup
tl;dr you need to use self for instance methods, but don't need it for class methods. A class may have many instances, but it can only have one declaration of itself (which also contains its type/class/static functions).
Why error occurs 1: Bare in mind the alertFunc could have had a reference to a property.
It could have been :
private func logAction () {
print("someProperty = \(self.someProperty)")
}
So, in this case it's obvious that you are eventually referencing a property.
Why error occurs 2: Even if you don't have a reference to self within your function, still because you wrote it as an instance method, the self is implicitly passed on. But, we don't see!
An instance method is really just syntactic sugar for a function that takes an instance for the first parameter, which is self passed automatically.
Under the hood it may look something like this :
private func alertFunc (_ instance: MyType) {
print("someProperty = \(instance.someProperty)")
}
// and actually the call to it *may* look something like this:
MyType.someFunc(self)
We never see the self being passed! It's a syntactic sugar that deceives us.
So, if your method does not use self internally (i.e. doesn't rely on the state of the instance in any way) then it's actually probably best to make it a static/type/class method or free function.
Alternative1: use a free function.
class someClass {
...
}
func freeFunc {
print("Hi this is a free function, written outside the scope of any class...")
}
And then within your closure you call it using freeFunc()
Alternative2: Use a class function.
class someClass {
...
class private func alertFunc() {
print("Hi this was a class function, see the class at the beginning of the func definition")
}
}
And then within your closure you call it using yourClassName.alertFunc()
But, why is it that class functions don't create memory cycles but instance functions do?
I'm glad you asked:
For instance mehtods, for each instance that you reach out to, there is a new memory location and generate a new memory cycle which would persist deallocations.
For class methods, for each time you reach out to the class/type methods you reach out to the same class/type method, and while you persist that class method, you won't be creating it over and over, it is only created once and done!
In objective-C (and C++) type methods:
When the app starts up, the system can fairly safely just pre-allocate ALL the instructions
for those type methods into memory along with their class pointers
so there’s little to no overhead calling those over and over and over again.
I imagine swift is doing the same thing
When you write logAction(), it implicitly means self.logAction(). (Methods are called on some instance; when you don't specify, it defaults to self.) So you are using self inside the closure, which means the closure captures self, and whether it captures a strong or weak reference has memory management implications.

Swift - what should the default values of properties be in the parent class?

Not sure if I worded this question correctly, but here's my issue: I have a base class and a subclass, and my base class should never be instantiated on its own (in other languages it would be abstract). I know abstract classes aren't a thing in Swift. I have some computed read-only properties that change what they return in each subclass; they are more or less customized constants. Firstly, are overridden computed properties the best way to handle this kind of thing? Secondly, if these variables need to get initialized, i.e. can't be nil, what should they be initialized to in the parent class? Is there a way to otherwise indicate that the parent class shouldn't be initialized on its own?
You probably should use protocol instead of base class in your case. All common implementation can be done in protocol extensions and you won't need to provide default values for constants - just specify required get methods in the protocol.

Why is 'init' not assignable?

I just read that the init method can't be used as a value. Meaning:
var x = SomeClass.someClassFunction // ok
var y = SomeClass.init // error
Example found on Language reference
Why should it be like that? Is it a way to enforce language level that too dirty tricks come into place, because of some cohertion or maybe because it interferes with another feature?
Unlike Obj-C, where the init function can be called multiple times without problems, in Swift there actually is no method called init.
init is just a keyword meaning "the following is a constructor". The constructor is called always via MyClass() during the creation of a new instance. It's never called separately as a method myInstance.init(). You can't get a reference to the underlying function because it would be impossible to call it.
This is also connected with the fact that constructors cannot be inherited. Code
var y = SomeClass.init
would also break subtyping because the subtypes are not required to have the same initializers.
Why should it be like that?
init is a special member, not a regular method.
Beyond that, there's no reason that you'd ever need to store init in a variable. The only objects that could use that function in a valid way are instances of the class where that particular init is defined, and any such object will have already been initialized before you could possibly make the assignment.
Initializers don't have a return value. In order to assign it to something, it should be able to return something - and it doesn't.