Hey all, got a couple questions from my first day ...
# getting-started
e
Hey all, got a couple questions from my first day of learning Kotlin. First off, I'm having an issue with JetBeans Intellij IDEA - when I create a new project after installing, it prompts me to select an android SDK to use, and when I click "download android sdk" it brings me to the download JDK window and if I chose any of the options there, it puts the IDE to an errored state where the SDK path and type is set to a java JDK option and can't be changed. I found a way around it, but there is no way to do it through the new project window/wizard thing. Wanted to find out if this is a known issue and if I should submit a bug report, or where I should take that - it's reproducible with a brand new installation of intellij. Second, is there any way of comparing or doing operations with Bytes and any type of Literal? I cant find any way of implicitly stating a literals type to being a Byte. Alternatively, what actually happens under the hood when performing .toByte on a static literal?
j
Are you actually trying to do android development or are you trying to create a plain Kotlin Project? For defining literals: https://kotlinlang.org/docs/numbers.html#literal-constants-for-numbers Kotlin will interpret your literal to be a byte if the expected type is a byte, i.e.
val b: Byte = 0x0F
or
Copy code
fun doSthWithByte(b: Byte) { TODO() }

fun main() { 
    doSthWithByte(0x00) //0x00 is a Byte literal here
}
If you are familiar with Java, you might assume
0x0F
to be an int literal, which is implicitly converted. -- That's not a thing in kotlin. A number literal's type is whatever matches the context. If you want something else, you need to explicitly convert it, e.g. by using
toByte
on the number. Regarding the implementation of
toByte
see the docs: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/to-byte.html The docs of the standard lib also (usually) contain a link to the source (when clicking the prior link, look for "(Common Source)" -- which leads you here: https://github.com/JetBrains/kotlin/blob/05896a42da04620a2e8ca35e952ff31c3c48aa9d/core/builtins/native/kotlin/Primitives.kt#L1097 -- which in this case is not overly helpful, but I hope you can find your way from there.
Also welcome to Kotlin! 😄
e
Hey @JaniruTEC Thanks so much for the reply, and for the Welcome! To clarify and avoid any XY problem links, what I want to do is create a variable of type Byte and then do comparisons on that variable, like so:
var x: Byte = 1
if ( x >= 1) print("Hello!")
I understand that this doesn't work as is, and I need to know how it could be possible
j
Give me a sec
e
Yep, and that's about as far as I got with others; I actually just discovered something strange - SOME comparisons work fine, as I just discovered, >= and <= as well as < or > work fine, its JUST == that doesnt work
I assume because kotlin is treating == as === works in some other languages; Because they arent the exact same type it doesn't work.
that or for some reason there is incomplete overloading
Copy code
val test: Byte = -5

if (test >= -4) print("Hello!")
if (test <= -4) print("Hello!")
if (test > -4) print("Hello!")
if (test < -4) print("Hello!")
if (test == -4) print("Hello!")
j
Now I got it figured out. 😄 As I said: Kotlin doesn't support implicit conversion. In Java, all Ints are Longs. In Kotlin you have to always convert them explicitly (there are some exceptions, but those can be considered a help from the compiler). The reasons are established in the link I posted. Also Kotlin's
==
operator is the same as
equals
in Java,
===
does identity comparision (as Java's
==
) Since
Int's ==
operator is only defined for Ints (to keep the general contract of the
equals
method), you need to convert the Int to a Byte or the Byte to an Int (size limitations apply) Since that contract doesn't apply to
>=
,
>
,
<
and
<=
they are overloaded to work with all number types. Because of that, your example works (but only because of one of the helpers):
Copy code
var x: Byte = 1
if (x >= 1) print("Hello!")
Alternatively you could convert the int to a byte:
Copy code
var x: Byte = 1
if (x >= 1.toByte()) print("Hello!")
... or convert the byte to an int
Copy code
var x: Byte = 1
if (x.toInt() >= 1) print("Hello!")
For equality, you have to use explicit conversions. For further reference, also see: https://kotlinlang.org/docs/numbers.html#explicit-number-conversions It's explained there far better
e
and now to the nitty gritty, I understand that the .toByte() will solve the problem with specifically the equality case, but what actually goes on when I write .toByte? I see the implementation you linked earlier but that doesnt tell me anything about the optimizations that get done under the hood, often times these types of functions get completely statically optimized away but other times they are nightmares of creating additional objects or variables, additional function calls, etc - the only time I would be working with bytes is to optimize something, and I do understand that this is more arcane knowledge than the average kotlin developer should ever care about or get into, but just for my brains sake I've gotta probe for it
j
I'd have to rely on some educated guesses from here on, but some notes: • Kotlin is a multi platform language, therefore I assume there is no definite answer to that • Since kotlin doesn't have the concept of non-object primitives (as opposed to Java's int), all numbers are theoretically objects • ... but this might not be true after compiler optimizations • ... and if that's actually not true after compiler optimizations, I would assume that Kotlin displays the same behavior as Java. AFAIK Java's implementation is rather efficient, only doing some bit-math • But finally: Apart from actual disk storage, I don't believe this optimization to actually do much for you on most platforms. IIRC 32 bit and 64 bit systems can't even address anything smaller than 32 and 64 bits respectively, which is an int/long in Kotlin.
e
looking into it, for javas implementation of a Byte, the optimizations made for the bytecode compilation for bytes is actually slower for several operations especially multiplication than it is for Int. This is fairly old information, I cant find anything more recent, but I think it's safe to say even in the most optimal situation, using bytes for operations is going to typically be slower than just using ints, and not use any less ram for kotlin to JVM or java, so the only case it would be better is purely for data storage or sending data over the network, both of which can be handled in-place. Ah well, thank you for giving me some starting points for digging and thanks for the detailed and informed responses
r
Regarding what happens under the hood when calling
Int.toByte()
, the link to the Kotlin sources provided by Dominik does provide one hint: the method is annotated with
@kotlin.internal.IntrinsicConstEvaluation
, which, according to the comments in the source has the following effect:
When applied to a function or property, enables a compiler optimization that evaluates that function or property at compile-time and replaces calls to it with the computed result.
Of course, like mentioned before, due to the fact that Kotlin is multiplatform, it still could depend on the compiler implementation 🙂
e
@Riccardo Lippolis Thanks so much! Thats what I figured would be the end result in general, and of course it depends on implementation which could be different for each type of target, but in general if that's been implemented I'm going to say it's safe to assume in even the most dire of cases .toByte will have exactly 0 influence on runtime speeds, it's too much ptsd from interpreted scripting languages I guess
although, looking into this has given me insight for why many interpreted languages care less about typesafety - type safety can typically be guaranteed at the compiler level for the majority of code, but with an interpreted language you either need to take drastic measures to GUARANTEE typesafety, or you just throw it out the window and make everything general. Like in javascript, you can store a function call or something like an inline function as a string, send that string over the network or something, and then execute it as valid code by treating it like a function of an object (do not do this)