I am looking at the solution for the gigasecond exercism exercise for Kotlin: http://exercism.io/exercises/kotlin/gigasecond/readme. I can understand how it needs two two constructor because LocalDate and LocalDateTime arguments are passed in when creating the class. What I don't understand is how the below secondary class constructor variables are passed in and used in the class. It seems like the calculation only happens when LocalDateTime arguments are passed in, as calculation is only done with dobWithTime. What magic is happening here ?
data class Gigasecond(val dobWithTime: LocalDateTime) {
constructor(dateOfBirth: LocalDate) : this(dateOfBirth.atStartOfDay())
val date: LocalDateTime = dobWithTime.plusSeconds(1000000000)
}
The secondary constructor just forwards the call to primary constructor with the : this() syntax, while creating the required LocalDateTime object from the LocalDate that it received as its parameter.
You could think of the secondary constructor as a function that does the following:
fun createGigaSecond(dateOfBirth: LocalDate): Gigasecond {
return Gigasecond(dateOfBirth.atStartOfDay())
}
Except it gets to use the usual constructor syntax instead, and so it can be called as Gigasecond(dataOfBirth) instead of createGigaSecond(dateOfBirth).
From the official documentation about secondary constructors:
If the class has a primary constructor, each secondary constructor needs to delegate to the primary constructor, either directly or indirectly through another secondary constructor(s). Delegation to another constructor of the same class is done using the this keyword.
This is what's happening here.
Related
I have some niggling questions about factory constructors example mentioned here (https://www.dartlang.org/guides/language/language-tour#factory-constructors).
I am aware of only three types of constructors on a basic level - default, named and parameterised.
Why should I use factory at all for this example?
Is that a named constructor which is being used? and why?
tl;dr Use a factory in situations where you don't necessarily want to return a new instance of the class itself. Use cases:
the constructor is expensive, so you want to return an existing instance - if possible - instead of creating a new one;
you only ever want to create one instance of a class (the singleton pattern);
you want to return a subclass instance instead of the class itself.
Explanation
A Dart class may have generative constructors or factory constructors. A generative constructor is a function that always returns a new instance of the class. Because of this, it does not utilize the return keyword. A common generative constructor is of the form:
class Person {
String name;
String country;
// unnamed generative constructor
Person(this.name, this.country);
}
var p = Person("...") // returns a new instance of the Person class
A factory constructor has looser constraints than a generative constructor. The factory need only return an instance that is the same type as the class or that implements its methods (ie satisfies its interface). This could be a new instance of the class, but could also be an existing instance of the class or a new/existing instance of a subclass (which will necessarily have the same methods as the parent). A factory can use control flow to determine what object to return, and must utilize the return keyword. In order for a factory to return a new class instance, it must first call a generative constructor.
In your example, the unnamed factory constructor first reads from a Map property called _cache (which, because it is Static, is stored at the class level and therefore independent of any instance variable). If an instance variable already exists, it is returned. Otherwise, a new instance is generated by calling the named generative constructor Logger._internal. This value is cached and then returned. Because the generative constructor takes only a name parameter, the mute property will always be initialized to false, but can be changed with the default setter:
var log = Logger("...");
log.mute = true;
log.log(...); // will not print
The term factory alludes to the Factory Pattern, which is all about allowing a constructor to return a subclass instance (instead of a class instance) based on the arguments supplied. A good example of this use case in Dart is the abstract HTML Element class, which defines dozens of named factory constructor functions returning different subclasses. For example, Element.div() and Element.li() return <div> and <li> elements, respectively.
In this caching application, I find "factory" a bit of a misnomer since its purpose is to avoid calls to the generative constructor, and I think of real-world factories as inherently generative. Perhaps a more suitable term here would be "warehouse": if an item is already available, pull it off the shelf and deliver it. If not, call for a new one.
How does all this relate to named constructors? Generative and factory constructors can both be either unnamed or named:
...
// named generative
// delegates to the default generative constructor
Person.greek(String name) : this(name, "Greece");
// named factory
factory Person.greek(String name) {
return Greek(name);
}
}
class Greek extends Person {
Greek(String name) : super(name, "Greece");
}
There is not much difference between a static method and a factory constructor.
For a factory constructor the return type is fixed to the type of the class while for a static method you can provide your own return type.
A factory constructor can be invoked with new, but that became mostly irrelevant with optional new in Dart 2.
There are other features like redirects rather rarely used that are supported for (factory) constructors but not for static methods.
It is probably still good practice to use a factory constructor to create instances of classes instead of static methods to make the purpose of object creation more obvious.
This is the reason a factory constructor is used in the example you posted and perhaps because the code was originally written in Dart 1 where it allowed to create a logger instance with new like with any other class.
Yes this is a named constructor and the prefix _ makes it a private named constructor. Only named constructors can be made private because otherwise there would be no place to add the _ prefix.
It is used to prevent instance creation from anywhere else than from the public factory constructor. This way it is ensured there can't be more than one Logger instance in your application.
The factory constructor only creates an instance the first time, and for subsequent calls always returns the previously created instance.
Complementing Dave's answer, this code shows a clear example when use factory to return a parent related class.
Take a look a this code from https://codelabs.developers.google.com/codelabs/from-java-to-dart/#3
You can run this code here. https://dartpad.dartlang.org/63e040a3fd682e191af40f6427eaf9ef
Make some changes in order to learn how it would work in certain situations, like singletons.
import 'dart:math';
abstract class Shape {
factory Shape(String type) {
if (type == 'circle') return Circle(2);
if (type == 'square') return Square(2);
// To trigger exception, don't implement a check for 'triangle'.
throw 'Can\'t create $type.';
}
num get area;
}
class Circle implements Shape {
final num radius;
Circle(this.radius);
num get area => pi * pow(radius, 2);
}
class Square implements Shape {
final num side;
Square(this.side);
num get area => pow(side, 2);
}
class Triangle implements Shape {
final num side;
Triangle(this.side);
num get area => pow(side, 2) / 2;
}
main() {
try {
print(Shape('circle').area);
print(Shape('square').area);
print(Shape('triangle').area);
} catch (err) {
print(err);
}
}
In addition to the other answers, also consider the order of instantiating objects and when the instance is created:
In normal constructor, an instance gets created and the final variables get instantiated with the initializer list. This is why there's no return statement. The instance to return is already fixed, when executing the constructor!
In a factory constructor, the instance to return is decided by the method. That's why it needs a return statement and why it'll usually call a normal constructor in at least one path.
So a factory does nothing different than a static method could do (in other languages often called getInstance()), except you cannot overload the constructor with a static method but you can with a factory method. I.e. factory methods are a way to hide the fact that the user of your class is not calling a constructor but a static method:
// C++
MyCoolService.getInstance()
// Dart
MyCoolService()
Assume we have the following primary and secondary constructors:
open class Animal(val name:String){
internal constructor(message:InputStream): this(readName(message))
}
Why is not possible to call the internal constructor of the super class?
class Dog(name:String):Animal(name){
internal constructor(message:InputStream):super(message)
^^^^^
Primary constructor call expected
}
edit
Obviously it compiles when the primary constructor is converted to a secondary constructor or removed at all.
class Dog:Animal{
constructor(name:String):super(name)
internal constructor(message:InputStream):super(message)
}
Is this a compiler bug?
From docs:
If the class has a primary constructor, each secondary constructor needs to delegate to the primary constructor, either directly or indirectly through another secondary constructor(s). Delegation to another constructor of the same class is done using the this keyword
and:
If the class has no primary constructor, then each secondary constructor has to initialize the base type using the super keyword, or to delegate to another constructor which does that.
Your Dog class has a primary constructor, so you have to delegate to that using this.
If you remove the primary constructor, you will be able to refer to super constructor:
class Dog : Animal {
constructor(message: InputStream) : super(message)
}
(the above raises no error)
I've got a method that accepts a parameter of type Class, and I want to only accept classes that extend SuperClass. Right now, all I can figure out to do is this, which does a run-time check on an instance:
public function careless(SomeClass:Class):void {
var instance:SomeClass = new SomeClass();
if (instance as SuperClass) {
// great, i guess
} else {
// damn, wish i'd have known this at compile time
}
}
Is there any way to do something like this, so I can be assured that a Class instance extends some super class?
public function careful(SomeClass:[Class extends SuperClass]):void {
var instance:SuperClass = new SomeClass();
// all is good
}
If you are going to instantiate it anyway, why not accept an object instead which allows you to type it to :SuperClass?
careless(SomeClass);
//vs.
careless(new SomeClass);
Not too much of a problem there as far as your code goes.
There are a few differences though:
The object has to be created, because an object is required. If your function does not instantiate the class under some circumstances, this can be a problem. Additional logic to pass either an object or null can bloat the function call.
If you cannot call the constructor outside that function, it won't
work either.
All that is solved by the factory pattern. Pass a factory as the parameter that produces SuperClass objects.
function careful(factory:SuperClassFactory)
Your requirements:
I want to only accept classes that extend SuperClass
and
I need to pass in a Class so that it can be instantiated many times
by other objects later
Can be met by passing in an instance of the class you need, and using the Object.constructor() method.
public function careful(someInstance:SuperClass):void {
//you probably want to store classRef in a member variable
var classRef: Class = someInstance.constructor();
//the following is guaranteed to cast correctly,
//since someInstance will always be a descendant of SuperClass
var myInst:SuperClass = new classRef() as SuperClass;
}
More reading here.
You can't do that in ActionScript 3. In languages like C# you can do something like (forgive me if the syntax is off):
public void Careless<T>() where T : SuperClass
But AS3 does not have 'generics'. Unfortunately the only way I know how to do what you want is the way you have already done.
A pattern that might be more suitable for your use case might be something like:
class SuperClass
{
public static function careless():void
{
var instance:SuperClass = new SuperClass();
// ...
}
}
The only way to have static type checking in ActionScript 3 is to provide an instance of a class.
It is possible but it's expensive. You can use on a Class (not instance) the:
flash.utils.describeType
You then get an XML with a bunch of information including inheritance for that class. Like I said it's an expensive process and probably creating an instance and checking it will be in most cases faster.
Is there any way for me to define implicit or explicit type conversions in ActionScript?
For instance, I want to define a conversion such that Array can cast into MyClass implicitly. If not, an explicit cast would be useful. I know I can always pass it into my constructor, but I am dealing with semantics here, and I am most interested in a conversion solution if it exists.
Type casting in ActionScript 3
Object(instanceOfOtherObject);
Works based on the valueOf property of the given class (if defined). Therefore, you can define your class MyClass as such:
package {
public class MyClass {
private var myArray:Array;
public function MyClass(inputArray:Array = null) {
myArray = (inputArray ? inputArray : new Array());
}
public function valueOf():Array {
return myArray;
}
}
}
Then you will be able to perform this typecasting:
var mc:myClass = new MyClass();
var arr:Array = Array(myClass);
To my knowledge, the reverse is not an option because the valueOf function of Array does not return an object of type MyClass. There is nothing stopping you from creating a CastableArray that extends and overrides the valueOf function of Array to make it return an instance of MyClass using the constructor I defined above, though you may run into other issues with other fundamental language components that expect an Array to return an Array in its valueOf property (comparison of objects comes to mind).
I have not done any particular testing with this next suggestion, but if MyClass extends from Array and does not define a valueOf function, it may still be possible to do the type conversion depending on the constructor of MyClass and what Flash does in circumstances when valueOf is not defined.
I have a service class which has overloaded constructors. One constructor has 5 parameters and the other has 4.
Before I call,
var service = IoC.Resolve<IService>();
I want to do a test and based on the result of this test, resolve service using a specific constructor. In other words,
bool testPassed = CheckCertainConditions();
if (testPassed)
{
//Resolve service using 5 paramater constructor
}
else
{
//Resolve service using 4 parameter constructor
//If I use 5 parameter constructor under these conditions I will have epic fail.
}
Is there a way I can specify which one I want to use?
In general, you should watch out for ambiguity in constructors when it comes to DI because you are essentially saying to any caller that 'I don't really care if you use one or the other'. This is unlikely to be what you intended.
However, one container-agnostic solution is to wrap the conditional implementation into another class that implements the same interface:
public class ConditionalService : IService
{
private readonly IService service;
public ConditionalService()
{
bool testPassed = CheckCertainConditions();
if (testPassed)
{
// assign this.service using 5 paramater constructor
}
else
{
// assign this.service using 4 parameter constructor
}
}
// assuming that IService has a Foo method:
public IBaz Foo(IBar bar)
{
return this.service.Foo(bar);
}
}
If you can't perform the CheckCertainConditions check in the constructor, you can use lazy evaluation instead.
It would be a good idea to let ConditionalService request all dependencies via Constructor Injection, but I left that out of the example code.
You can register ConditionalService with the DI Container instead of the real implementation.
My underlying problem was that I was trying to resolve my class which had the following signature:
public DatabaseSchemaSynchronisationService(IDatabaseService databaseService, IUserSessionManager userSessionManager)
This was basically useless to me because my usersessionmanager had no active NHibernate.ISession because a connection to my database had not yet been made. What I was trying to do was check if I did have a connection and only then resolve this class which served as a service to run database update scripts.
When changing my whole class to perform the scripts in a different way, all I needed in its constructor's signature was:
public DatabaseSchemaSynchronisationService(ISessionFactory sessionFactory)
This allowed me to open my own session. I did, however have to first check if the connection was ready before attempting to resolve the class, but having IDatabaseSchemaSynchronisationService as a parameter to another class's constructor; this class also gettting resolved somewhere where I could not check the db connection was a bad idea.
Instead in this second class, I took the IDatabaseSchemaSynchronisationService paramater out of the constructor signature and made it a local variable which only gets instantiated (resolved) :
if (connectionIsReady)
Thanks to everyone who answered.