Consider the following Kotlin implementation of a string builder:
class StringBuilder {
private val items = mutableListOf<String>()
fun append(item: String): StringBuilder {
items.add(item)
return this
}
override fun toString(): String {
return items.joinToString("")
}
}
The internal implementation of the StringBuilder requires a mutable list of items, but if you wanted to take immutability seriously, you could easily refactor this to be completely immutable; for example:
class StringBuilder(private val items: List<String> = emptyList()) {
fun append(item: String): StringBuilder {
return StringBuilder(items + item)
}
override fun toString(): String {
return items.joinToString("")
}
}
According to Wikipedia, listed under Disadvantages
Builder classes must be mutable.
This clearly isn't the case; as demonstrated, a builder can be designed to be completely immutable, and the fact that this statement is listed under "Disadvantages" would suggest that it would be advantageous for builders to be immutable.
So, I was wondering if there are any specific reasons why builder implementations should be mutable?
I could only think of one reason - the garbage collection overhead for an immutable builder will be higher as new instances of the builder have to be returned each time.
Disadvantages of the Builder pattern include: (3)
...
Builder classes must be mutable.
...
The referenced presentation in that Wiki for that bullet point does not say "builder classes must be mutable" or list it as a disadvantage. So I find the placement of that reference to be misleading.
I think your point about garbage collection overhead is the only disadvantage in languages like Kotlin? (Aside from the inconvenience of ensuring you deep copy your fields in complex builders)
Your immutable example is the way a builder would be implemented in a pure functional language. As you said though, the issue is all the extra allocations and associated CPU cycles.
Related
I wrote an extension function to get an element of an JSON object by its name:
fun JSONObject.obj (name: String): JSONObject? =
try { this.getJSONObject(name) }
catch (e: JSONException) { null }
Now I want to extend this for nested JSON objects. I wrote the following:
tailrec fun JSONObject.obj (first: String, vararg rest: String): JSONObject? =
if (rest.size == 0)
obj(first)
else
obj(first)?.obj(rest[0], *rest.drop(1).toTypedArray())
But this looks quite inefficient to me.
What is the best way to slice a vararg argument?
We could use vararg only in the public function, but then internally use list for recursion:
fun JSONObject.obj (first: String, vararg rest: String): JSONObject? = obj(first, rest.asList())
private tailrec fun JSONObject.obj (first: String, rest: List<String>): JSONObject? =
if (rest.size == 0)
obj(first)
else
obj(first)?.obj(rest[0], rest.subList(1, rest.size))
Both asList() and subList() don't copy data, but only wrap the existing collection. Still, this is far from ideal, because it creates a new object for each iteration and it may create a chain of views (it depends on internal implementation of subList()). Alternatively, the internal function could receive an array and offset - this will solve both above problems.
Generally, I suggest to not try turning Kotlin into something it is not. It has limited support for functional constructs, but it is not a functional language. Without the linked list implementation which could be easily split into head and tail, this style of code will be always inefficient and/or cumbersome. You can look for such implementation, for example in Arrow or kotlinx.collections.immutable. The latter has ImmutableList with optimized subList() - you can use it with the solution provided above to avoid creating a chain of lists.
Update
As a matter of fact, basic lists implementations in the Java stdlib also provide optimized subList(): AbstractList.java. Therefore, the above solution using simply asList() should be fine, at least when targeting JVM.
Instead of slicing, why don't you try just iterating over all the objects and getting the JSONObjects? I think this would be much more efficient.
fun JSONObject.obj(vararg names: String): JSONObject? {
var jsonObject = this
for (name in names) {
if (!jsonObject.has(name))
return null
jsonObject = jsonObject.getJSONObject(name)
}
return jsonObject
}
I have 2 simple classes in kotlin
package com.sample.repo
class SampleClassA() {
fun test(): String {
return "Do things A way"
}
}
package com.sample.repo
class SampleClassB() {
fun test(): String {
return "Do things B way"
}
}
Now i have a configuration file that tells me which class to use.
Let's say i have a string
val className = "SampleClassA" // assuming all classes are in same package
I want obtain this class and invoke the test function in it
I was able to do below
fun `some random test`() {
val className = "SampleClassA"
val packageName = "com.sample.repo"
val kClass = Class.forName("$packageName.$className").kotlin
val method = kClass.members.find { it.name == "test" }
// How do i call this method ??
}
}
You should create an object of the class and then call method on it.
Example:
//...code from your example
val method = kClass.members.find { it.name == "test" }!!
val obj = kClass.primaryConstructor?.call()
val result = method.call(obj)
println(result)
I wouldn't do it that way. Instead, I'd require that the classes you're choosing between implement some common interface, which you can then refer to directly. For example:
interface Testable {
fun test(): String
}
package com.sample.repo
class SampleClassA() : Testable {
override fun test() = "Do things A way"
}
package com.sample.repo
class SampleClassB() : Testable {
override fun test() = "Do things B way"
}
fun `some random test`() {
val className = "SampleClassA"
val packageName = "com.sample.repo"
val testable = Class.forName("$packageName.$className").kotlin
.createInstance() as Testable
testable.test()
}
I don't know if this applies to OP, but judging from some of the questions asked here on StackOverflow, many people are coming to Kotlin from weakly-typed languages where it's common to use ‘string typing’ to fudge the lines between types, to assume that developers can always be trusted, and that it's fine to discover problems only at runtime. Of course, it's only natural to try to apply the patterns and techniques you're familiar with when learning a new language.
But while that style of programming is possible in Kotlin (using reflection), it's rarely a good fit. If you'll excuse one of my standard rants, reflection is slow, ugly, fragile, insecure, and hard to maintain; it's easy to get wrong, and forces you to handle most errors at runtime. Don't get me wrong: reflection is a very valuable tool, and there are situations where it's vital, such as writing frameworks, plug-ins, some forms of dependency injection, build tools, and similar. But reflection should be a tool of last resort — for general application coding, there's almost always a better approach, usually one that's more concise, easier to read, performs better, spots more problems at compile-time, can be autocompleted in your IDE, and works with the language and its type system, not against it.
Kotlin is a strongly-typed language; it has a fairly sophisticated type system (and type inference, so you don't need to keep repeating yourself), which is safer and smarter, turns many errors into compile-time errors, allows many optimisations, and is effectively self-documenting (making more explicit the contract between called code and its callers). It's better to try to work with the type system when you can, rather than subvert if (which is what reflection does).
The example above uses reflection to create an instance of a class which is assumed to implement the Testable interface (and will give ugly errors at runtime if the class isn't available, doesn't implement that interface, or doesn't have a public constructor with no required params), but after that uses normal, typed code which is much safer.
(In fact, depending how your test code is structured, you might find a way to configure it with Testable instances rather than String classnames, and avoid reflection altogether. That would be simpler and safer still.)
I'm exploring the Substitution principal and from what I've understood about the principal is that a sub type of any super type should be passable into a function/class. Using this idea in a new section of code that I'm writing, I wanted to implement a abstract interface for a Filter like so
interface Filter {
fun filter(): Boolean
}
I would then imagine that this creates the contract for all classes that inherit this interface that they must implement the function filter and return a boolean output. Now my interpretation of this is that the input doesn't need to be specified. I would like it that way as I want a filter interface that guarantee the implementation of a filter method with a guarantee of a return type boolean. Does this concept even exists in Kotlin? I would then expect to implement this interface like so
class LocationFilter {
companion object : Filter {
override fun filter(coord1: Coordinate, coord2: Coordinate): Boolean {
TODO("Some business logic here")
}
}
}
But in reality this doesn't work. I could remove remove the filter method from the interface but that just defeats the point of the whole exercise. I have tried using varargs but again that's not resolving the issue as each override must implement varargs which is just not helpful. I know this may seem redundant, but is there a possibility to have the type of abstraction that I'm asking for? Or am I missing a point of an Interface?
Let's think about it a little. The main point of abstraction is that we can use Filter no matter what is the implementation. We don't need to know implementations, we only need to know interfaces. But how could we use Filter if we don't know what data has to be provided to filter? We would need to use LocationFilter directly which also defeats the point of creating an interface.
Your problem isn't really related to Kotlin, but to OOP in general. In most languages it is solved by generics/templates/parameterized types. It means that an interface/class is parameterized by another type. You use it in Kotlin like this:
interface Filter<in T> {
fun filter(value: T): Boolean
}
object LocationFilter : Filter<Coordinate> {
override fun filter(value: Coordinate): Boolean {
TODO()
}
}
fun acquireCoordinateFilter(): Filter<Coordinate> = LocationFilter
fun main() {
val coord: Coordinate = TODO()
val filter: Filter<Coordinate> = acquireCoordinateFilter()
val result = filter.filter(coord)
}
Filter is parameterized, meaning that we can have a filter for filtering strings (type is: Filter<String>), for filtering integers (Filter<Int>) or for filtering coordinates (Filter<Coordinate>). Then we can't use e.g. Filter<String> to filter integers.
Note that the code in main() does not use LocationFilter directly, it only knows how to acquire Filter<Coordinate>, but the specific implementation is abstracted from it.
Also note there is already a very similar interface in Java stdlib. It is called Predicate.
my interpretation of this is that the input doesn't need to be specified.
Where did you get that interpretation from?
You can see that it can't be correct, by looking at how the method would be called. You should be able to write code that works for any instance of Filter — and that can only happen if the number and type of argument(s) is specified in the interface. To use your example:
val f: Filter = someMethodReturningAFilterInstance()
val result = f.filter(coord1, coord2)
could only work if all implementations used two Coordinate parameters. If some used one String param, and others used nothing at all, then how would you call it safely?
There are a few workarounds you could use.
If every implementation takes the same number of parameters, then you could make the interface generic, with type parameter(s), e.g.:
interface Filter<T1, T2> {
fun filter(t1: T1, t2: T2): Boolean
}
Then it's up to the implementation to specify which types are needed. However, the calling code either needs to know the types of the particular implementation, or needs to be generic itself, or the interface needs to provide type bounds with in variance.
Or if you need a variable number of parameters, you could bundle them up into a single object and pass that. However, you'd probably need an interface for that type, in order to handle the different numbers and types of parameters, and/or make that type a type parameter on Filter — all of which smells pretty bad.
Ultimately, I suspect you need to think about how your interface is going to be used, and in particular how its method is going to be called. If you're only ever going to call it when the caller knows the implementation type, then there's probably no point trying to specify that method in the interface (and maybe no point having the interface at all). Or if you'll want to handle Filter instances without knowing their concrete type, then look at how you'll want to make those calls.
The whole this is wrong!
First, OOP is a declarative concept, but in your example the type Filter is just a procedure wrapped in an object. And this is completely wrong.
Why do you need this type Filter? I assume you need to get a collection filtered, so why not create a new object that accepts an existing collection and represents it filtered.
class Filtered<T>(private val origin: Iterable<T>) : Iterable<T> {
override fun iterator(): Iterator<T> {
TODO("Filter the original iterable and return it")
}
}
Then in your code, anywhere you can pass an Iterable and you want it to be filtered, you simply wrap this original iterable (any List, Array or Collection) with the class Filtered like so
acceptCollection(Filtered(listOf(1, 2, 3, 4)))
You can also pass a second argument into the Filtered and call it, for example, predicate, which is a lambda that accepts an element of the iterable and returns Boolean.
class Filtered<T>(private val origin: Iterable<T>, private val predicate: (T) -> Boolean) : Iterable<T> {
override fun iterator(): Iterator<T> {
TODO("Filter the original iterable and return it")
}
}
Then use it like:
val oddOnly = Filtered(
listOf(1, 2, 3, 4),
{ it % 2 == 1 }
)
I have the following code but I am convinced that it could be simpler/more elegant
package org.example
import javax.enterprise.context.ApplicationScoped
#ApplicationScoped
object CanceledRequestsHandler {
var identifiers = setOf<String>()
fun add(id: String){
var mutableIdentifiers = identifiers.toMutableList()
mutableIdentifiers.add(id)
this.ids = mutableIds.toSet()
}
}
I wanted to limit the mutability. Any suggestions t improve my code?
There is a more elegant way! Try this script file (.kts) with kotlinc (or you can run it within IDEA):
object CanceledRequestsHandler {
var ids = setOf<String>()
override fun toString(): String = ids.toString()
fun add(id: String){
ids = ids + id
}
}
System.err.println(CanceledRequestsHandler);
CanceledRequestsHandler.add("foo");
CanceledRequestsHandler.add("bar");
System.err.println(CanceledRequestsHandler);
A bit of explanation:
The + operator can be applied to collections, and works as one might expect -- returns a new collection (see https://kotlinlang.org/docs/reference/collection-plus-minus.html).
I'm not sure what your separate identifiers variable was, but you can use a single var that contains an immutable Set to do your job here.
As a commenter and the accepted answer point out, there's more you can do. If you're trying to limit mutability entirely to add(), you can lock this down further, with something like this:
object CanceledRequestsHandler {
private var _ids = mutableSetOf<String>()
val ids
get() = _ids.toSet()
override fun toString(): String = ids.toString()
fun add(id: String) {
_ids.add(id)
}
}
System.err.println(CanceledRequestsHandler);
CanceledRequestsHandler.add("foo");
CanceledRequestsHandler.add("bar");
System.err.println(CanceledRequestsHandler);
// Below line does not compile
// CanceledRequestsHandler.ids.add("baz")
Now the only way the ids property can change is via the add() method.
I wanted to limit the mutability
Converting immutable collection to mutable on each data mutation is not a limitation of mutablility, it's just overhead. The worst here is that property is declared as mutable (var). This design may lead to data loss in multi-thread case.
If data mutation is unavoidable, then it's better to have mutable (concurrent in multi-thread case) data collection with immutable property (val).
Even better way to limit mutability will be using a mutable data structure only for a short initialization period, and then freezing it into immutable (see buildSet), but I'm not sure that this approach is applicable in your case.
Due in part to the fact that I cannot create data classes without parameters in Kotlin, I use objects for those cases, e.g.
sealed class Node {
object Leaf : Node()
data class Branch(val left:Node, val right:Node) : Node()
}
The issue is that sometimes, I end up with multiple instances of the Leaf class. Obviously this should not generally happen, but it occurs when serializing and deserializing with some frameworks and with some test cases.
Now, you might argue that I should fix those cases, but it's hard to know where they might be, and not always possible or desirable to modify the deserialization semantics of frameworks.
As such, I want all instances of my objects to act as the same value, much like a parameter-less data class would (or a parameterless case class in Scala).
My best solution so far is the following, included in every object I create that might encounter this issue:
object SaneLeaf {
override fun hashCode() = javaClass.hashCode()
override fun equals(other: Any?) = other?.javaClass == javaClass
}
Obviously, this is verbose and error prone, since it doesn't seem possible to abstract away those implementations to an interface. A super-class would work in cases where the object doesn't need to extend another class, but that's often not the case.
Alternatively, I can create a data class with a Nothing parameter. But that seems like even more of a hack.
How have others dealt with this issue? Are there plans to add hashCode and equals implementations to objects that follow the presumed semantics of those classes (all instances should be equal / same hashCode)?
I believe having multiple instances of an object's underlying class is really an issue you should fix, but there's a simpler workaround that allows you to have the equality semantics you described.
You can define an abstract class that performs the equality logic and make the sealed class inherit from it, like this:
abstract class SingletonEquality {
override fun equals(other: Any?): Boolean =
this::class.objectInstance != null && other?.javaClass == this.javaClass ||
super.equals(other)
override fun hashCode(): Int =
if (this::class.objectInstance != null)
javaClass.hashCode() else
super.hashCode()
}
And the usage:
sealed class Node : SingletonEquality() {
object Leaf : Node()
data class Branch(val left:Node, val right:Node) : Node()
}
Here, Leaf will inherit the equals implementation from SingletonEquality and get compared just the way you want.