I don't know if this has been discussed before but...
# language-proposals
s
I don't know if this has been discussed before but I couldn't find it anywhere so... I'd really like to make comparisons and assignments a bit more idiomatic with the following changes: Comparisons: Similar to Python, numeric comparisons should be more mathematical. Like
if (1 <= x <= 10) // do something
This would greatly improve readability and would reduce bugs since it's easier to understand that x is within the boundaries of 1 and 10. Way better than the current equivalent:
if (1 <= x && x <= 10)
. The "&& x" is just boilerplate code here... Assignments: For assignments I'd like to have the possibility of assigning an assignment to another variable. E.g.
myObject.apply { inputFee = outputFee = 1.0 }
In this case both inputFee and outputFee would be set to 1.0 (or more like inputFee would be set to outputFee). This is useful for mapping code so it makes most sense for properties. I could also imagine like saving a property to a variable before it is modified in someway. Maybe like this:
Copy code
val before = myObject.counter = someArg
myObject.count() // modifies counter
val difference = myObject.counter - before
What do you guys think?
g
When I see
val before = myObject.counter = 0
my mind tries to auto correct to
val before = myObject.counter == 0
.
😁 1
for comparisons, I would us
x in 1..10
☝🏻 10
a
Copy code
val before = myObject.counter = 0
How is the associativity working here? In the first example, you said
inputFee
and
outputFee
would both be initialised to 0. But in the second example, you seem to assume that
myObject.counter
would be initialised to 0 and
before
would get its previous value. So is
a = b = c
interpreted as
a = (b = c)
or
(a = b) = c
? It seems reasonable to unroll
before
in your second example, as it should always be 0.
s
Sorry the second example might not be that good. Yes, before would be zero which, in this case doesn't make sense. If you had an argument instead of 0 it would make more sense.
n
in C and C++, your "before" code doesn't work
a
I don’t see a benefit over
Copy code
val before = myObject.counter
myObject.counter = someArg
myObject.count() // modifies counter
val difference = myObject.counter - before
Especially if the compiler can’t make any guarantee about atomicity of myObject.counter, which would be the interesting thing here imho.
n
before would get the new value of myObject.counter
Well, the benefit is not repeating myObject.counter
that said, this can be easily solved
Copy code
fun <T> T.exchange(new: T): T {
    val old = this
    this = new
    return old
}
ah actually you probably can't do
this = new
can you
s
What does C++ have to do with this? 😄 The benefit would just be a more concise way to set two variables to the same value. I often encounter this with mapping code.
n
probably because C, which you may heard of, and is slightly influential in the language design space, has that syntax
s
Yes but in lots of ways I think it isn't. E.g. does C have val and var?
n
and it also sets two variables, but with difference precedence.
It doesn't, but that's not really the main point. But maybe I misunderstood your second example
i'm not sure if you want
before
to be the same as somearg
or
before
to be the value of
myObject.counter
, before someArg is assigned
s
I want it to be the same as
someArg
.
All three variables would then be equal. In the second example
myObject.counter
gets changed which doesn't affect
before
since it's a primitive type. So 1. set
myObject.counter
to
someArg
2. set
before
to
myObject.counter
which is now equal to
someArg
Does this help?
Is this equivalent to C? (I don't know that syntax in C)
n
yep, equivalent to C
s
Also another example for comparisons where
x in 1..10
doesn't quite cut it: Assume you have two variables
a
and
b
, with this syntax you could easily compare them like:
1 <= a < b <= 10
.
Meaning both variables need to be within 1 to 10 and
a
has to be smaller than
b
.
n
I guess it's just a question of how often this really comes up, how much work is it to implement, and how much of an improvement is it really
you can easily implement something like containsAll for example. So you could do:
Copy code
1..10.containsAll(a, b) && a < b
I'm not even sure this is less clear than the original
assignment is trickier, kotlin doesn't really let you abstract much over assignment, so it's basically your suggestion vs a small amount of repetition
however, people have talked about allowing destructuring to work for assigning existing variables as well as creating new ones. If that were possible, then it would be possible to write a nice function to assign multiple objects to the same value
s
I think both makes Kotlin a little more mathematical which would boost it's use for data science a bit. I agree that it's not a huge language improvement and it's not going to be used widely but it can be a handy addition for some cases and it reduces boilerplate code.
g
Is the proposal to allow
val foo = var bar = 0
?
n
@Sebastian Brunner doesn't it become a headache for the parser though at some point?
parsing wise it's not trivial, it means arbitrary look-ahead on comparison operators
s
Yes I think that's be some work...
Guillermo that's up for debate. I primarily see it to assign properties so no var or val is required. And for variables your proposal could be an possibility, but since it doesn't make much sense to have the second variable (
bar
) be val it could also implicitly be var...
n
I feel like arbitrary look ahead on comparison operators might be too high a price for the gain. The whole language is very tooling oriented, tooling depends on parsing fast.
b
For multiple assignment, you could do something like this:
Copy code
inline class Assign<out T>(private val value: Any?) {
    inline operator fun component1(): T = value as T
    inline operator fun component2(): T = value as T
    inline operator fun component3(): T = value as T
    inline operator fun component4(): T = value as T
    //...
}

inline fun <T> assign(value: T) = Assign<T>(value)
And use it like this:
Copy code
val (x, y, z) = assign(5)
I don't think you can use it to assign existing vars though
n
I think you can just do that with a List can't you
Copy code
fun <T> assign(t: T) = listOf(t, t, t, t, t)
i think lists offer componentN up to 5
b
You could do it like that, but my way doesn't instantiate anything (since it's an inline class). That way creates a new List instance.
n
i thought inline classes were experimental? I also admit to not caring much about this kind of optimization
I'm also not sure why
value
is
Any?