What's the real intention behind Kotlins also scope function - kotlin

I'm asking myself what the language designers intention behind the also scope function was and if almost everyone is misusing it.
If you search here on stack overflow for examples of Kotlins scope functions, you'll end up with this accepted answer: https://stackoverflow.com/a/45977254/5122729
The given answer for also { } is
also - use it when you want to use apply, but don't want to shadow
this
class FruitBasket {
private var weight = 0
fun addFrom(appleTree: AppleTree) {
val apple = appleTree.pick().also { apple ->
this.weight += apple.weight
add(apple)
}
...
}
...
fun add(fruit: Fruit) = ... }
Using apply here would shadow this, so that this.weight would refer to
the apple, and not to the fruit basket.
That's also the usage I see quite often. But if I have a look into the documentation at kotlinlang.org, they are clearly saying:
also is good for performing some actions that take the context object
as an argument. Use also for additional actions that don't alter the
object, such as logging or printing debug information. Usually, you
can remove the calls of also from the call chain without breaking the
program logic.
From that point of view, the given example would be wrong as it would break the program logic if it is removed. For me, also is kind of Javas peek (doc), which is there, but should not be used for productive program logic.
Can someone enlighten me?

After having a longer discussion on Reddit about this topic, the documentation was adjusted in a way were the sentence
Usually, you can remove the calls of also from the call chain without
breaking the program logic.
was removed. See the corresponding PR: https://github.com/JetBrains/kotlin-web-site/pull/1676

Related

Doing this on kotlin is a bad practice?

The second way is a little smaller but i dont know if this is okay, can i use also just for be able to use expression body and put the first line of the cod on the side of method name?
override fun findOrdensColeta() {
view.setProgressBarVisibility(View.VISIBLE)
model.findOrdensColeta {
handleFindOrdensColeta()
}
}
override fun findOrdensColeta() = view.setProgressBarVisibility(View.VISIBLE).also {
model.findOrdensColeta {
handleFindOrdensColeta()
}
}
Yes, I think the second version is bad style. I see no good reasons to use also() like that, and several reasons not to:
also() is intended for use within expressions, where you don't have the option of adding a separate statement. (The classic case is logging a value before doing something with it.) That doesn't apply here, where two simple statements work just as well. So there's no benefit other than conciseness; using also() here is unnecessary complexity.
The second version has an expression body, which looks like it returns a useful value — but it actually returns the result of calling setProgressBarVisibility(), which is presumably Unit just like the first version. So the expression body is highly misleading.
Also, the only reason that the second version is shorter is that the first statement has been squeezed onto the same line. I don't think that's justified here* — it joins two things (the function signature and the call to setProgressBarVisibility()) that aren't directly related, and it makes the line too long for most people to read easily. (I'm surprised you find the second version easier to read. I tend to prefer conciseness, but even I find the first version a good deal easier to read — probably because it falls into a very familiar pattern that doesn't need any extra thought.)
If you cared only about reducing the number of lines, then the first version could be written like this (not recommended!):
override fun findOrdensColeta() { view.setProgressBarVisibility(View.VISIBLE)
model.findOrdensColeta {
handleFindOrdensColeta()
}
}
(You could join even more lines, perhaps squeezing it all onto a single line if you wanted to make it completely unreadable!)
Conversely, if there were other good reasons for using the second version, it would be better if wrapped like this:
override fun findOrdensColeta()
= view.setProgressBarVisibility(View.VISIBLE).also {
model.findOrdensColeta {
handleFindOrdensColeta()
}
}
So as you can see, the difference in length is mainly due to the (unjustified and confusing) line-joining, not the use of also().
So using also() here has no real benefit, as well as some significant drawbacks.
* I'm not saying you should never put the function body on the same line as its signature. That can work well if the body is an expression that's short enough to fit neatly all one line. For example:
override fun toString() = "MyClass(val1 = $val1)"
However, if that makes the line very long, or wraps onto further lines, or is a function body, then it's almost always more readable to start the body on the next line in the traditional fashion.
I believe the second one is a bad approach.
also is designed to provide the ability to modify or use the receiver and return it afterwards.
In your case, also is not containing any usages of its receiver (which is the result of view.setProgressBarVisibility(View.VISIBLE) ). Therefore it is not needed here
The second version is a bit confused to me - if you take the first one as the standard way to do things, a simple code block with two statements in it, what benefit does the second one really give you? You're basically using expression syntax to make it a one-liner - but it's not a one-liner, so you have to add a scope function just to give yourself back the curly braces so you can add another line of code!
So this:
override fun findOrdensColeta() {
view.setProgressBarVisibility(View.VISIBLE)
model.findOrdensColeta {
handleFindOrdensColeta()
}
}
Does exactly the same thing as this:
override fun findOrdensColeta() = view.setProgressBarVisibility(View.VISIBLE).also {
model.findOrdensColeta {
handleFindOrdensColeta()
}
}
But with the latter
it appears to return a result from setProgressBarInvisibility because it's a single-expression function (the original clearly returns nothing)
the use of also which passes that result value through reinforces the idea that you're trying to return that result
the also block implies you're using that value for something (otherwise why's it there?) and it takes a moment to see that you're not
when you realise none of the above are true, now you might be wondering if you're missing something, or if the original coder intended something specific but made a mistake
Because the basic function block is so simple and readable and a natural fit for what you're doing, doing something else can throw up some questions, or be confusing to read. Sure the way it's formatted you've saved a single line, but now it's harder to understand, y'know?
This is something to watch out for in Kotlin I think (and I'm guilty of this myself) - being able to chain stuff together sometimes encourages people to go for "one-liners" that are hard to follow, but hey at least you didn't (explicitly) create a variable! That's not what you're doing here (you're creating an unnecessary variable actually!) but it feels like a similar thing - trying to make a single expression instead of doing things the old-school way.
Coding is about trying to strike that balance between simplicity and readability, and elegant efficiency, and a lot of it's about learning what tools and tricks are available, and knowing when to use them (and how best to do it) and when to avoid them. At the end of the day it's a style choice and this is just my opinion (although all the other commenters so far are saying similar things) but hopefully it's given you something to think about! I've been there too - including using expressions for functions that don't return a value at all - but I think that's all part of learning a language and the things it offers you

Kotlin [1..n] constructor parameter

Is there a way to enforce 1..* parameters in Kotlin that will still allow the spread operator?
I've tried:
class Permission(
// 1..n compliance
accessiblePage: Webpage,
vararg accessiblePages: Webpage
) {
And that does enforce 1..*, but it also means that Permission(*pages) won't work, so that's a pretty awkward interface.
Is there an easy way to enforce 1..* without a runtime constructor error?
There is, unfortunately, no way to check this in Kotlin at compile time aside from the way you mentioned. Since vararg parameters are really just syntactic sugar for an array, your code is essentially
class Permission (
accessiblePage: Webpage,
accessiblePages: Array<Webpage>
)
So the question then becomes "Can you ensure that an array has at least one element in it at compile time?" For most languages, that's a clear no, although the Kotlin team did at one point experiment with it:
[C]urrently, Kotlin compiler doesn't collect static information about
collections size. FYI, at some point Kotlin team tried to collect such
information and use it for warnings about possible
IndexOutOfBoundException and stuff like that, but it was found that
there were a very little demand on such diagnostics in real-life
projects, so, given complexity of such analysis, it was abandoned[.]
(https://github.com/Kotlin/KEEP/issues/139#issuecomment-405551324)
It's possible that this metadata will be added at some point, but you shouldn't expect it soon.
That said, you could always combine a runtime check in the case of an Array with an overloaded signature in the case of varargs. This would mean that your vararg example would work the same, but passing an array to the function would subject it to a runtime check (you'd also not have to use the spread operator anymore):
class Permission (
accessiblePage: Webpage
vararg accessiblePages: Webpage
) {
constructor(accessiblePages: Array<Webpage>) {
require(accessiblePages.isNotEmpty()) {
"Must have at least one accessible page."
}
}
}
called like
val permission1 = Permission(Webpage(), Webpage())
val permission2 = Permission() // Would fail at compile time
val pages = arrayOf()
val permission3 = Permission(pages) // Would fail at runtime. Note also the lack of the spread operator.

Kotlin: Difference between {} and () while using map transform?

I'm new to kotlin. Ive always used the map transform with curly braces. Then -
Why does this work ->
val x = someList.map(::SomeConstructor)
and this doesn't?
val x = someList.map{ ::SomeConstructor }
I didn't find usage of map with circular brackets anywhere on the online tutorials.
Please try to explain in detail, or provide suitable reference article.
What you ask is explained in this official documentation.
If and only if the last argument of a function is a lambda, you can extract it from the call paranthesis, to put it inline on the right of the function. It allows a nicer DSL syntax.
EDIT: Let's make an example :
One of the good use-case is context programming. Imagine you've got a closeable object. You want to delimit its usage to ensure it's properly closed once not needed anymore. In Java, you've got the try-with-resources:
try (final AutoCloseable myResource = aquireStuff()) {
// use your resource here.
}
Kotlin provide the use function. Now, you can do either :
acquireStuff().use( { doStuff1(it) ; doStuff2(it) } )
or write :
acquireStuff().use {
doStuff1(it)
doStuff2(it)
}
It looks like a Java try-w-resource, but is extensible to any of your API. Allowing you to design libraries giving advanced constructs to end-users.

Math Parser/Lexer - Token interface design

Currently working on a small pet project, a Math Parser/Lexer and eventually solver for fun/learning. I've bashed out a basic prototype and am now looking to convert this into TypeScript to clean things up. Prototype can be found here https://github.com/chips5k/math-solver-prototype for those interested.
I am trying to come up with a clean interface based approach to dealing with my Tokens. I suspect i am looking at this the wrong way, but hopefully someone can offer useful advice.
In my TS design i have several interfaces, the base interface being Token, with NumericToken and FunctionToken extending these. I then have several classes that implement these interfaces such as: AdditionToken, VariableToken, NumberToken, PiToken, SineToken etc...
My problem is that in order to work with these interfaces i end up requiring methods to check the basic type e.g isNumeric, isFunction, isVariable or alternatively a direct type === TokenFactory.NUMERIC etc... This, to me, feels wrong as it basically voids the point of using an interface. I suspect that there is a nicer/cleaner more polymorphic approach i could take but unfortunately i'm out of ideas and have been unable to find info on what i am doing.
An example of where things fall apart shows itself when attempting to solve a series of tokens:
if(t.isFunction()) {
var a = stack.unshift();
var b = stack.unshift();
if(a.isNumeric() && b.isNumeric()){
result.push(tokenFactory.create(t.evaluate<number>(a.evaluate<number>, b.evaluate<number>));
} else {
//return to stack and move on, e.g can't solve x + 1 directly
}
} else {
stack.push(t);
}
Basically looking for what is considered the ideal approach for handling a scenario like this, and i suspect it may be an alternate approach to the design.
TIA!
basic type e.g isNumeric, isFunction, isVariable or alternatively a direct type === TokenFactory.NUMERIC etc... This, to me, feels wrong
Nope. This is fairly idiomatic as the type controls what functionality is there.
E.g you will see the TypeScript checker.ts littered with check on .kind (SyntaxKind) which is at TypeScript AST nodes discriminator.
Also you might want to consider adding a visitor that is recursive e.g.
function visit(item){
if (item.addition) {
return visit(item.left) + visit(item.right)
}
if (item.literal) {
return literal.value();
}
// ETC.
}

Why use a single incrementer class

Below code are found in WebKit:
RefPtr<Element> element = pendingScript.releaseElementAndClear();
if (ScriptElement* scriptElement = toScriptElement(element.get())) {
NestingLevelIncrementer nestingLevelIncrementer(m_scriptNestingLevel);
IgnoreDestructiveWriteCountIncrementer ignoreDestructiveWriteCountIncrementer(m_document);
//Do something else...
}
}
NestingLevelIncrementer is a simple class, which increase the counter in construction and decrease it in destruction. You could check the implementation here.
In this scrap, I think that is similar with increasing and reducing the number directly. Perhaps the only benefit is no matter to reduce the number then, but one new class is introduced.
Any other reason to use this pattern?
The intent is for the increment to be reversed no matter how the something else concludes; the stack variable will be destroyed when the method returns or an exception is thrown.
An alternative approach in other languages would use try...finally; see this for more discussion on RAII in C++ vs. finally:
Does C++ support 'finally' blocks? (And what's this 'RAII' I keep hearing about?)