Swift subclassing - how to override Init() - initialization

I have the following class, with an init method:
class user {
var name:String
var address:String
init(nm: String, ad: String) {
name = nm
address = ad
}
}
I'm trying to subclass this class but I keep getting errors on the super.init() part:
class registeredUser : user {
var numberPriorVisits: Int
// This is where things start to go wrong - as soon as I type 'init' it
// wants to autocomplete it for me with all of the superclass' arguments,
// and I'm not sure if those should go in there or not:
init(nm: String, ad: String) {
// And here I get errors:
super.init(nm: String, ad: String)
// etc....
Apple's iBook has examples of subclassing, but none those feature classes that have an init() method with any actual arguments in it. All their init's are devoid of arguments.
So, how do you do this?

In addition to Chuck's answer, you also have to initialize your new introduced property before calling super.init
A designated initializer must ensure that all of the properties
introduced by its class are initialized before it delegates up to a
superclass initializer. (The Swift Programming Language -> Language Guide -> Initialization)
Thus, to make it work:
init(nm: String, ad: String) {
numberPriorVisits = 0
super.init(nm: nm, ad: ad)
}
This simple initialization to zero could have been done by setting the property's default value to zero too. It's also encouraged to do so:
var numberPriorVisits: Int = 0
If you don't want such a default value it would make sense to extend your initializer to also set a new value for the new property:
init(name: String, ads: String, numberPriorVisits: Int) {
self.numberPriorVisits = numberPriorVisits
super.init(nm: name, ad: ads)
}

In swift 2.0 and Later it works like this (all cases)
init(newString:String) {
super.init(string:newString)
// Designed initialiser
}
override init(someString: String) {
super.init(mainString: someString)
// Override initialiser when subclass some class
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
// Some boilerplate code to handle error (needed when override)
}
convenience init(newString:String, withParameters:Dictionary<String,String>) {
self.init(someString:newString)
//Convenience initialiser
}

You pass arguments to an initializer much like you pass arguments to a normal method:
init(nm: String, ad: String) {
super.init(nm: nm, ad: ad)
}
For reference, this is shown in the Designated and Convenience Initializers In Action section of the Swift Language Guide.

Have you tried setting a value to numberPriorVisits and changing the types for the calls to super
class user {
var name:String
var address:String
init(nm: String, ad: String) {
name = nm
address = ad
}
}
class registeredUser : user {
var numberPriorVisits: Int;
init(nm: String, ad: String) {
self.numberPriorVisits = 0;
super.init(nm: nm, ad: ad)
}
}

Related

Failure to discover property with reflection

Taking the following minimal example:
type IMyInterface =
interface
abstract member Name: string with get
end
let testInstance =
{ new IMyInterface with
member _.Name = "Hello Word" }
I would have naively expected a call to testInstance.GetType().GetProperties() to contain a PropertyInfo element corresponding to Name.
However, only an empty array is returned.
Using testInstance.GetType().GetProperty("Name") yields no better as it simply returns a <null> object.
More confusing still, Visual Studio 2022 IntelliSense lists Name as a valid property (as I'd expect).
How can I get a PropertyInfo corresponding to the Name property?
In F# all interface implementations are private. This means that interface methods and properties do not appear as methods and properties of the implementing class.
In C# this works a bit differently: if you define a public member that happens to match an interface member, you don't have to explicitly tell the compiler that it's meant to be the interface implementation, the compiler will map it to the interface automatically for you.
So, for example, if you write this:
class MyClass : IMyInterface {
public string Name { get; }
}
The C# compiler will actually compile it as this:
class MyClass : IMyInterface {
public string Name { get; }
string IMyInterface.Name { get { return this.Name; } }
}
(well, it's not exactly like that, but you get the idea)
But the F# compiler doesn't do that. If you want a class property in addition to the interface property, you have to roll one yourself:
type MyClass() =
member __.Name = "Hello Word"
interface IMyInterface with
member this.Name = this.Name
But if you just want the interface property, you can get it off of the interface type:
let nameProp = typeof<IMyInterface>.GetProperty("Name")
let helloWorld = nameProp.GetValue testInstance
Or, if you don't know the interface type in advance, you can get it from the object type as well:
let intf = testInstance.GetType().GetInterfaces().[0]
let nameProp = intf.GetProperty("Name")
let helloWorld = nameProp.GetValue testInstance

Ignoring some default values for serialization

tl;dr; In Newtonsoft JSON.NET, how do you ignore default values for some types (enums), and not others (ints)?
My team is consuming a library that uses protocol buffers for their business entities. Every enumeration in this library/protobuf has a default value of 0, "ValueNotSet". My team is using Newtonsoft JSON.NET to serialize these entities. Here's a diluted example for a bakery's inventory:
public enum Flavor { ValueNotSet, Cherry, Blueberry, Cheese };
public class DanishInventory { public int QtyInStock; public Flavor; }
In order to conserve resources we do not want to serialize ValueNotSet (the real world scenario has many enumerations), but having zero cheese danishes in stock is valid and we do want to serialize zero. Because of this, we cannot use DefaultValueHandling = Ignore in settings.
I created a custom JsonConverter, but by the time WriteJson(...) is called the key is already in the JsonWriter. So if I write nothing the JSON is invalid, and I don't see an obvious method to back-track the writer to overwrite a key. So what is the best way to ignore default values for some types (e.g. enums), but not others (e.g. ints)?
Note that the enums are in a NuGet package and cannot be modified, e.g. by adding attributes.
You can use a variation of the DefaultValueContractResolver from this answer to Json.NET: How to make DefaultValueHandling only apply to certain types? to exclude all enum-valued properties with default values:
public class EnumDefaultValueContractResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
if (property.DefaultValueHandling == null)
{
if (property.PropertyType.IsEnum)
{
//For safety you could check here if the default value is named ValueNotSet and only set IgnoreAndPopulate in that case.
//var defaultValue = Enum.ToObject(property.PropertyType, 0);
//if (defaultValue.ToString() == "ValueNotSet")
//{
property.DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate; // Or DefaultValueHandling.Ignore if you prefer
//}
}
}
return property;
}
}
Then use it as follows:
var resolver = new EnumDefaultValueContractResolver();
var settings = new JsonSerializerSettings { ContractResolver = resolver };
var json = JsonConvert.SerializeObject(inventory, settings);
You may want to cache the contract resolver for best performance.
Demo fiddle here.
Many serializers, (including Json.NET I believe) support the ShouldSerialize*() pattern; if you don't mind doing this on a per-usage basis, you could do:
public class DanishInventory {
public int QtyInStock;
public Flavor;
public bool ShouldSerializeFlavor() => Flavor != 0;
}

Flow type for a function parameter that is instance of a class

Given:
// #flow
declare interface IFoo {
test();
}
class Foo implements IFoo {
test () {
console.log('in test');
}
}
if i had a function:
// some function
async function demo (argA: string, argB: INSTANCE_OF_Foo) { ... }
how can i tell flow that argB is "instance of class that implements IFoo"? in other words if the usage of function demo had to be like
const foo: IFoo = new Foo();
demo('bla' foo);
How can i ensure what get's passed to demo is instance of a class that implements IFoo?
type script interface is ignored at runtime, it is only used at compile time for type checking. So there is no way you can check whether the Foo is implemented with IFoo.
But you can check whether foo is an instance of Foo class.
So it depends on what you seek: you can either ensure the argument implements IFoo:
async function demo (argA: string, argB: IFoo)
, or the argument is an instance of the class Foo:
async function demo (argA: string, argB: Foo)
But I must say, it's not really clear why you need to require an instance instead of an interface (which I think is the way to go here).
You can play with this easily at flow.org/try.
Hope this helps!

Kotlin bound callable references inconsistency

Today I was creating unit tests for my Presenter in Android app and I noticed some inconsistency with bound callable references. Is it under development or is it language bug? I found that in kotlin 1.1 bound callable references are supported. But my code fails with kotlin 1.1.2-4.
In my presenter class, tested method reads data from database and dao.getAllItems() method have no parameters while view takes list --> view.showData(List<Item>).
I'm using Mockito, RxJava2 and Room Persistance library.
class ItemsPresenter #Inject constructor(private val itemDao: ItemDao) : Presenter<ItemsView>
{
val TAG = this.javaClass.name!!
private val disposables: CompositeDisposable = CompositeDisposable()
private lateinit var view: ItemsView
override fun onCreate(view: ItemsView)
{
this.view = view
}
override fun onDestroy()
{
disposables.clear()
}
fun onGetItems()
{
Observable.fromCallable(itemDao::getAllItems)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ data -> view.showData(data) },
{ throwable -> view.showLoadingDataError(throwable.localizedMessage) }
)
}
}
I have created test for onGetItems() method
#RunWith(KotlinTestRunner::class)
class ItemsPresenterTest
{
private lateinit var view: ItemsView
private lateinit var dao: ItemDao
private lateinit var presenter: ItemsPresenter
#Before
fun setup()
{
RxAndroidPlugins.setInitMainThreadSchedulerHandler { Schedulers.io() }
dao = mock(ItemDao::class.java)
view = mock(ItemsView::class.java)
presenter = ItemsPresenter(dao)
}
#Test
fun onGetItemsTest()
{
val list = ArrayList<Item>()
When(dao.getAllItems()).thenReturn(list)
presenter.onCreate(view)
presenter.onGetItems()
verify(dao).getAllItems()
verify(view).showData(list)
}
}
When I have setup as above, the test passes without problems. But when I change line
{ data -> view.showData(data) }
to
{ view::showData }
Then my test fails saying
Wanted but not invoked:
itemsView.showData([]);
Is it language bug? Because vulnerable code compiles fine and runs, it just causes the method to not be invoked at all, without any errors.
To clarify, the same code written in Java 8 works fine, lambda argument is correctly passed into method reference. As you can see in Kotlin bound callable references work fine when used with methods that takes no parameters, otherwise they are not called at all.
You should change
{ data -> view.showData(data) }
to
(view::showData)
to pass in the method reference correctly. This way, with (), you're passing in the method reference as the parameter of the subscribe method.
Using {}, you define a new function with a lambda to be given to the subscribe method.
Writing down
{ view::showData }
is equivalent to
{ it -> view::showData }
which is a function that ignores its parameter, and returns the method reference view::showData.

Interfaces stored as value; Methods unable to update struct fields

I have a tool that I'm writing that exposes some functions that pull information out of a static database to several scripting languages that I'm embedding into the tool.
I thought; "Hey sounds like a nice use case for interfaces". So I defined an interface like so in my package scripting
type ScriptingLang interface {
RunScript(filename string) error
RunString(s string) error
Interpreter() error
Init() error
IsInit() bool
}
Then I store a map of them so I can look them up by a string defined like so in a different package.
var ScriptingLangs = make(map[string]scripting.ScriptingLang)
and a function to register them. Also some little helper functions like
func RunString(lang, s string) error {
if v, ok := ScriptingLangs[lang]; ok {
if !v.IsInit() {
v.Init()
}
return v.RunString(s)
} else {
return NoSuchLangErr
}
return nil
}
The problem that I ran into is it seams that interfaces can't have methods with pointer receivers. As a result my Lua struct that implements ScriptingLang isn't able to save it's *state because it's stored in ScriptingLangs.
I've tried updating the value stored in the map at the end of functions that save state and it didn't update the value.
To my understanding you shouldn't use pointers of interfaces so what are my options here? I would like to really keep the interfaces so I can do some neat stuff with git submodules.
A minimal example of my problem:
package main
import (
"fmt"
)
type ScriptingLang interface {
DoString(s string) error
Init() error
}
type Lua struct {
state string
}
func (l Lua) DoString(s string) error {
fmt.Printf("Doing '%v' with state '%v'\n", s, l.state)
return nil
}
func (l Lua) Init() error {
l.state = "Inited"
return nil
}
var lang ScriptingLang
func main() {
lang = Lua{}
lang.Init()
lang.DoString("Stuff")
}
If you want to mutate state, you need a pointer receiver, and your Init method doesn't have one. The fact that you're storing the value inside an interface makes no difference.
In your minimal(-ish) example, change the Init method (and any method that updates state) to have a pointer receiver, and point a pointer inside the interface and everything works:
func (l *Lua) Init() error {
l.state = "Inited"
return nil
}
...
func main() {
lang = &Lua{}
lang.Init()
lang.DoString("Stuff")
}
This article might help: http://jordanorelli.com/post/32665860244/how-to-use-interfaces-in-go

Resources