I have a class with a nested, private class. I have a Builder, standard Java builder pattern, that constructs instances of this class. I don't want anyone outside of my class to be able to see my hidden class.
In Java I could do this:
public class Example {
private SneakyType doNotExposeThis;
private Example(Builder builder) {
// OK 'cause in Java you can access the private
// members of a nested class
doNotExposeThis = builder.doNotExposeThis;
}
private static class SneakyType {
SneakyType(String x) {
// stuff
}
}
public static class Builder {
private SneakyType doNotExposeThis;
public void addFoo(String something) {
doNotExposeThis = new SneakyType(something);
}
public Example build() { return new Example(this); }
}
}
But I can't figure out how to do the same in Kotlin:
class Example(builder: Builder) {
private lateinit var doNotExposeThis: SneakyType
init {
doNotExposeThis = builder.doNotExposeThis
}
class Builder {
// If private or internal I can't access it in Example.init
// and if public it gets exposed.
val doNotExposeThis: SneakyType
fun addFoo(something: String) {
// actual construction is quite a bit more complex
doNotExposeThis = SneakyType(something)
}
}
}
Note that for the sake of Java interop I want to keep my builder. I also want it because my object is complicated to construct and I want it to be immutable so I have a builder with lots of setters, adders, vals, etc. and then in init I construct a single immutable Example.
The only alternatives I see are:
Instead of have a SneakyType in my builder save all the info necessary to construct one and then construct it in Example. Works but adds a ton of complexity.
Give up on Example being immutable and allow the builder to call into it to set up a Sneaky
Expose the Sneaky
Is there no way to mimic the Java version?
I see two viable options:
Use the internal visibility modifier:
class Example private constructor(builder: Builder) {
private val doNotExposeThis: SneakyType
init {
doNotExposeThis = builder.doNotExposeThis
}
internal class SneakyType(x: String)
class Builder {
internal lateinit var doNotExposeThis: SneakyType
fun addFoo(something: String) {
doNotExposeThis = SneakyType(something)
}
fun build(): Example {
return Example(this)
}
}
}
This will make SneakyType only visible within your Kotlin compilation module.
Make Example independent of its builder (this is what I recommend):
class Example private constructor(private val doNotExposeThis: SneakyType) {
private class SneakyType(x: String)
class Builder {
private lateinit var doNotExposeThis: SneakyType
fun addFoo(something: String) {
doNotExposeThis = SneakyType(something)
}
fun build(): Example {
return Example(doNotExposeThis)
}
}
}
Related
It is code worked in java but after convert to kotlin it does not compile.
Having a base class which has some defines as static protected member in the companion object:
abstract class ParentClass {
companion object {
#JvmField
final protected val SERVICE_TYPE_A = "the_service_type_a"
}
}
and the child class:
class ChildClass: ParentClass {
public override fun getServiceType(): String {
return SERVICE_TYPE_A. //<== got compile error
}
}
it does not compile.
how to access a parent class static protected member from subclass?
You need to use #JvmStatic instead as follows:
abstract class ParentClass {
companion object {
#JvmStatic
protected val SERVICE_TYPE_A = "the_service_type_a"
}
abstract fun getServiceType(): String
}
The final keyword in SERVICE_TYPE_A is redundant since everything is final by default in Kotlin. This also mean that if you want ParentClass to be extended, then you need to explicitly define it as open.
Then your ChildClass would look as follows:
class ChildClass: ParentClass() {
override fun getServiceType(): String {
return SERVICE_TYPE_A
}
}
Imagine that I try to build simple dependency injection lib. Its Injector class, when called on a specific class, should inject all properties annotated with #Service annotation.
For example, given this client:
class ClientA {
#Service private lateinit var service1: Service1
#Service private lateinit var service2: Service2
private lateinit var service3: Service3
}
a call to injector.inject(ClientA()) should result in service1 and service2 being set (but not service3). Let's assume that Injector knows how to construct these objects.
My question is how to write the code that parses class' properties, checks their annotations and sets them in Kotlin?
Since I'm on Android, I tried to go through Java reflection:
fun inject(client: Any) {
val clientClass = client::class.java
val fields = clientClass.declaredFields
for (field in fields) {
if (isAnnotatedForInjection(field)) {
injectField(client, field)
}
}
}
private fun isAnnotatedForInjection(field: Field): Boolean {
val fieldAnnotations = field.annotations
for (annotation in fieldAnnotations) {
if (annotation is Service) {
return true
}
}
return false
}
The problem is that fieldAnnotations is empty. Converting ClientA's code to Java I see the following:
public final class ClientA {
private Service1 service1;
private Service2 service2;
private Service3 service3;
/** #deprecated */
// $FF: synthetic method
#Service
private static void service1$annotations() {
}
/** #deprecated */
// $FF: synthetic method
#Service
private static void service2$annotations() {
}
}
Looks like Kotlin compiler creates static methods to aggregate properties' annotations. With this info, I can write some ugly code to make it work using Java's reflection API, but there must be a cleaner way, right?
If you want to place the annotation on the field, you can use #field:Service.
Let's say I created a class which extends from another class and I want to override one of the parent functions but I want this function to be private from outside (like protected in Java).
I tried to use protected as it says here but it doesn't work.
Is it possible with Kotlin?
open class YesNoDialog(context: Context, styleRes: Int) : Dialog(context, styleRes) {
protected fun setTexts() {
}
}
class MultiSelectDialog(context: Context, styleRes: Int):YesNoDialog(context, styleRes) {
}
In this example I want to access setTexts from MultiSelectDialog class
It can be done with protected, but you also need to add open to allow it to be overridden:
open class YesNoDialog(context: Context, styleRes: Int) : Dialog(context, styleRes) {
protected open fun setTexts() {
}
}
class MultiSelectDialog(context: Context, styleRes: Int) : YesNoDialog(context, styleRes) {
override fun setTexts() {
}
}
I am confused how delegation works in Kotlin. Wikipedia says:
With language-level support for delegation, this is done implicitly by having self in the delegate refer to the original (sending) object, not the delegate (receiving object).
Given the following Code:
interface BaseInterface {
fun print()
}
open class Base() : BaseInterface {
override fun print() { println(this) }
}
class Forwarded() {
private val base = Base()
fun print() { base.print() }
}
class Inherited() : Base() {}
class Delegated(delegate: BaseInterface) : BaseInterface by delegate
fun main(args: Array<String>) {
print("Forwarded: ")
Forwarded().print();
print("Inherited: ")
Inherited().print();
print("Delegated: ")
Delegated(Base()).print();
}
I get this output:
Forwarded: Base#7440e464
Inherited: Inherited#49476842
Delegated: Base#78308db1
I'd expect Delegated to return Delegated because self/this should refer to the original object. Do I get it wrong or is Kotlins delegation different?
Kotlin delegation is very simple - it generates all interface methods and implicitly invokes it on delegated object, except for methods explicitly overriden by the user.
Your example is functionally the same as:
class Delegated(delegate: BaseInterface) : BaseInterface{
// when generating bytecode kotlin assigns delegate object to internal final variable
// that is not visible at compile time
private val d = delegate
override fun print(){
d.print()
}
}
So it's pretty clear why it prints Base.
I think this is easiest to understand if we look at the decompiled Java bytecode this gets compiled into:
You can do this by going to Tools > Kotlin > Show Kotlin Bytecode and then clicking Decompile
public final class Delegated implements BaseInterface {
// $FF: synthetic field
private final BaseInterface $$delegate_0;
public Delegated(#NotNull BaseInterface delegate) {
Intrinsics.checkParameterIsNotNull(delegate, "delegate");
super();
this.$$delegate_0 = delegate;
}
public void print() {
this.$$delegate_0.print();
}
}
So when you do interface delegation what happens is that Kotlin creates field for the delegate named $$delegate_0 and adds methods in your delegating class which will operate on $$delegate_0. You can have multiple delegates as well, they will get their own fields. There is one caveat though: you can't access $$delegate_0 directly, not even if you make it a var like this:
class Delegated(var delegate: BaseInterface) : BaseInterface by delegate
This will compile to:
public final class Delegated implements BaseInterface {
#NotNull
private BaseInterface delegate;
// $FF: synthetic field
private final BaseInterface $$delegate_0;
#NotNull
public final BaseInterface getDelegate() {
return this.delegate;
}
public final void setDelegate(#NotNull BaseInterface var1) {
Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
this.delegate = var1;
}
public Delegated(#NotNull BaseInterface delegate) {
Intrinsics.checkParameterIsNotNull(delegate, "delegate");
super();
this.$$delegate_0 = delegate;
this.delegate = delegate;
}
public void print() {
this.$$delegate_0.print();
}
}
sadly. I've written about this topic here.
I'm trying to follow along with a C# design patterns book by writing my code in TypeScript. Perhaps this is my first mistake, but it's a way I enjoy to learn a language.
TypeScript doesn't support the abstract keyword for classes, so I am trying to simulate it. Maybe this is my second mistake.
Here is my interface and classes:
interface IEngine {
getSize(): number;
getTurbo(): boolean;
}
class AbstractEngine implements IEngine {
constructor(private size: number, private turbo: boolean) {
throw "Abstract class";
}
public getSize(): number {
return this.size;
}
public getTurbo(): boolean {
return this.turbo;
}
public toString(): string {
var funcNameRegex = /function (.{1,})\(/;
var results = (funcNameRegex).exec(this.constructor.toString());
var className = (results && results.length > 1) ? results[1] : '';
return className + " (" + this.size + ")";
}
}
class StandardEngine extends AbstractEngine {
constructor(size: number) {
// not turbo charged
super(size, false);
}
}
When trying to instantiate an AbstractEngine with new AbstractEngine(1, true) I get an "Abstract class" error as expected.
When trying to instantiate a StandardEngine with new StandardEngine(9000) I also get an "Abstract class" error.
Is there a way I can simulate an abstract class in TypeScript, have it unable to be instantiated, but still call super in a class that extends it? And what about simulating abstract methods, can I protect those and still call the super method?
As of today, TypeScript 1.6 is live and has support for the abstract keyword.
abstract class A {
foo(): number { return this.bar(); }
abstract bar(): number;
}
var a = new A(); // error, Cannot create an instance of the abstract class 'A'
class B extends A {
bar() { return 1; }
}
var b = new b(); // success, all abstracts are defined
I advise you not to do that. When the TypeScript compiler will implement a mechanism for abstract function, it is time to use it. But hacks that work at runtime are incomprehensible and degrade performance.
The interfaces are the great strength of TypeScript. They should be used massively.
Your example should be written like this:
interface Engine {
getSize(): number;
getTurbo(): boolean;
}
class StandardEngine implements Engine {
constructor(private size: number, private turbo: boolean) {
}
public getSize(): number {
return this.size;
}
public getTurbo(): boolean {
return this.turbo;
}
}
The simplest solution is often the best.
If you want to reuse code without a parent class which would then necessarily usable, the Handbook suggests Mixins. Mixins are a way of coping skills from several distinct entities.
Or with modules it is possible to keep private implementation (and therefore organize it as you want it) and export only interfaces and factories. An example:
module MyEngineModule {
export interface Engine {
getSize(): number;
getTurbo(): boolean;
}
export interface StandardEngine extends Engine {
}
export function makeStandardEngine(size: number, turbo: boolean): StandardEngine {
return new ImplStandardEngine(size, turbo);
}
// here classes are private and can inherit or use mixins…
class ImplEngine {
constructor(private size: number, private turbo: boolean) {
}
public getSize(): number {
return this.size;
}
public getTurbo(): boolean {
return this.turbo;
}
}
class ImplStandardEngine extends ImplEngine implements StandardEngine {
}
}
console.log(MyEngineModule.makeStandardEngine(123, true).getSize());
When calling the StandardEngine constructor, you have a call to super(size, false). This call into the base class is what is generating the second "Abstract class" error.
To simulate an abstract base class that will throw when instantiated, create an Init function that is called from your derived class.
class AbstractEngine implements IEngine {
private _size: number;
private _turbo: boolean;
constructor() {
throw "Abstract class";
}
init(size:number, turbo: boolean) {
this._size = size;
this._turbo = turbo;
}
}
class StandardEngine extends AbstractEngine {
constructor(size: number) {
// not turbo charged
// do not call super here
init(size, false);
}
}
An alternative solution would be to user a property that if set indicates that the constructor is being called from a child class it is safe to continue. This is shown below :
class AbstractEngine {
safe; // IMPORTANT : do not initialize
constructor(private size: number, private turbo: boolean) {
if(!this.safe) throw "Abstract class"; // IMPORTANT
}
}
class StandardEngine extends AbstractEngine {
constructor(size: number) {
this.safe = true; // IMPORTANT
super(size, false);
}
}