unsigned data types could be nice for array access. Usually the indexes are unsigned anyway. But currently I cannot directly do this. E.g. this code.
val foo = 1.toUInt()
"foo"[foo]
fails to compile with:
error: type mismatch: inferred type is UInt but Int was expected
what is the best way to deal with this? Sure I could do:
val foo = 1.toUInt()
"foo"[foo.toInt()]
but this feels wrong somehow. UInt is an inline class anyway and gets erased to Int anyway - so I think this should not be needed. Anyone saw a kotlin/KEEP for this?
Also wondering about how to define unsigned constants. Unfortunately the constructor is private so I cannot do e.g.
const val foo = UInt(42)
and
const val foo = 42.toUInt()
fails with 42.toUInt() is not a constant value
Unless/until there's built-in support for this, you can easily add it yourself. For example, for standard arrays:
operator fun <T> Array<T>.get(index: UInt) = this[index.toInt()]
And for CharSequences (which aren't arrays):
operator fun CharSequence.get(index: UInt) = this[index.toInt()]
With that in scope, your "foo"[foo] works fine!
(You'd also need separate overloads for IntArray &c if you used those.)
In the array indexing question, .toInt() is the best method I have found.
Declaring a const, you can append a "u" to any integer constant, or "uL" for a long constant, like 42u or 1_000_000_000_000uL.
Related
I am trying to create List<Char> from String in Kotlin but it seems there is no inbuilt function is provided by lib. Also casting will generate error. So here is what I am doing. Please let me know if I am missing something in question. (Or we can say converting string to List<Char> in Kotlin).
var stringVal = "ABC"
var genList:List<Char> = arrayListof()
var count = 0
while (stringVal.length == genList.size) {
// way to add stringVal to genList
count++
}
The answer given by #Moira is definitely the way to go here, I would accept it.
However, the question was about adding an element to a List<Char>, which isn't possible in Kotlin because a List is immutable and yours gets initialized as an empty one, so it will stay empty.
Use a MutableList<Char> and simply add single Chars to it if you need it:
fun main(args: Array<String>) {
var genList = mutableListOf<Char>()
genList.add('a')
genList.add('A')
genList.add('B')
genList.add('C')
println(genList)
}
Output:
[a, A, B, C]
val chars = "ABC".toList()
CharSequence has a to(Mutable)List extension function defined in kotlin.text.
fun CharSequence.toList(): List<Char>
Returns a List containing all characters.
kotlin-stdlib / kotlin.text / toList
fun CharSequence.toMutableList(): MutableList<Char>
Returns a MutableList filled with all characters of this char sequence.
kotlin-stdlib / kotlin.text / toMutableList
Kotlin's standard libraries have hundreds of utility functions like this, so chances are that most of the time what you want already exists.
Many standard types that conceptually model some sort of iterable data, but are not Iterable, have extensions defined on them that are equivalent to those in kotlin.collections.
Does the fact that this doesn't compile mean that they're not quite first class types?
fun foo(s: String): Int = s.length
// This won't compile.
val bar = foo
Is there a way to do this without resorting to OO?
Does the fact that this doesn't compile mean that they're not quite first class types?
No, it doesn't.
In Kotlin, to reference a function or a property as a value, you need to use callable references, but it is just a syntax form for obtaining a value of a function type:
fun foo(s: String): Int = s.length
val bar = ::foo // `bar` now contains a value of a function type `(String) -> Int`
Once you get that value, you are not limited in how you work with it, which is what first-class functions are about.
You can use reference to the function :::
fun foo(s: String): Int = s.length
val bar = ::foo
And then invoke it:
bar("some string")
Suppose I have the following function definition.
fun<T> parse(a: Any): T = when (a) {
is String -> a
else -> false
}
I guessed it should be valid. However, the IntelliJ IDEA linter shows a type mismatch error
That being said, I would change the return type of my parse function to Any, right? So that, what is the difference between using Any type and Generics in Kotlin? In which cases should use each of those?
I did read the following question but not understood at all about star-projection in Kotlin due to the fact I am quite new.
Your return type it defined as T, but there is nothing assuring that T and a:Any are related. T may be more restrictive than Any, in which case you can't return a boolean or whatever you provided for a.
The following will work, by changing the return type from T to Any:
fun<T> parse(a: Any): Any = when (a) {
is String -> a
else -> false
}
Any alternate option, if you really want to return type T:
inline fun<reified T> parse(a: Any): T? = when (a) {
is T -> a
else -> null
}
Your example does not use T and thus it's nonsense to make it generic anyways.
Think about this: As a client you put something into a function, e.g. an XML-ByteArray which the function is supposed to parse into an Object. Calling the function you do not want to have it return Any (Casting sucks) but want the function return the type of the parsed object. THIS can be achieved with generics:
fun <T> parse(xml: ByteArray): T {
val ctx: JAXBContext = JAXBContext.newInstance()
val any = ctx.createUnmarshaller().unmarshal(ByteArrayInputStream(xml))
return any as T
}
val int = parse<Int>("123".toByteArray())
val string = parse<String>("123".toByteArray())
Look at the method calls: You tell with generics what type is expected to be returned. The code is not useful and only supposed to give you an idea of generics.
I guessed it should be valid
Why would it be? You return a String in one branch and a Boolean in the other. So the common type for the entire when expression is Any and that's what the compiler (and IDEA) says is "found". Your code also says it should be T (which is "required").
Your generic method should work for any T, e.g. for Int, but Any isn't a subtype of Int and so the code isn't valid.
So that, what is the difference between using Any type and Generics in Kotlin?
This is like asking "what is the difference between using numbers and files": they don't have much in common in the first place. You use generics to write code which can work with all types T (or with all types satisfying some constraint); you use Any when you want the specific type Any.
I noticed that I can convert a double value into an integer like this.
var array = kotlin.arrayOfNulls<Int>(10)
for( i in array.indices ){
array[i] = ( Math.random().toInt() )
}
If Math.random() returns a double value, how can a double value have a method named toInt()? Are numerical values also objects?
Yes, instances of numeric types are Kotlin objects. Quoting from the Kotlin docs:
In Kotlin, everything is an object in the sense that we can call member functions and properties on any variable. Some types are built-in, because their implementation is optimized, but to the user they look like ordinary classes.
In practice, non-nullable instances (e.g. Double as opposed to Double?) are represented under the hood with JVM primitives.
In Java, any object that extends Number has the ability to invoke intValue. I would presume that Kotlin is exposing that API there.
The Kotlin compiler aims to use primitives as much as possible. This means using primitives unless a variable is nullable or has to be boxed because generics are involved. (Docs)
In the case of these conversion functions (.toInt(), .toLong(), etc.), the variables that these functions are called on will be primitives, and simple casts will be used on them in the bytecode. So there's no boxing happening here, these are still primitives, but you can call "functions" on them as syntactic sugar.
Math.random().toInt() // Kotlin
(int) Math.random(); // Generated bytecode decompiled to Java
In case an otherwise primitive value is assigned to a nullable variable, such as in your case (assigned to an array element which is of type Int?), it will be boxed using a valueOf call at the assignment:
val n: Int? = 25
Integer n = Integer.valueOf(25);
So your specific assignment will be a combination of the two above examples, and will translate like this:
array[i] = Math.random().toInt()
array[i] = Integer.valueOf((int) Math.random());
In case you're interested in a simpler replacement for your example code:
You can use an IntArray (primitive array, int[] in Java) instead of an Array<Int> (array of boxed values, Integer[] in Java). You can also initialize it in the constructor's second parameter using a lambda.
var array = IntArray(10) { Math.random().toInt() }
This is roughly equivalent to this Java code:
int[] array = new int[10];
for (int i = 0; i < 10; i++) {
array[i] = (int) Math.random();
}
In Scala, you can overload a method by having methods that share a common name, but which either have different arities or different parameter types. I was wondering why this wasn't also extended to the return type of a method? Consider the following code:
class C {
def m: Int = 42
def m: String = "forty two"
}
val c = new C
val i: Int = C.m
val s: String = C.m
Is there a reason why this shouldn't work?
Thank you,
Vincent.
Actually, you can make it work by the magic of 'implicit'. As following:
scala> case class Result(i: Int,s: String)
scala> class C {
| def m: Result = Result(42,"forty two")
| }
scala> implicit def res2int(res: Result) = res.i
scala> implicit def res2str(res: Result) = res.s
scala> val c = new C
scala> val i: Int = c.m
i: Int = 42
scala> val s: String = c.m
s: String = forty two
scala>
You can of course have overloading for methods which differ by return type, just not for methods which differ only by return type. For example, this is fine:
def foo(s: String) : String = s + "Hello"
def foo(i: Int) : Int = i + 1
That aside, the answer to your question is evidently that it was a design decision: the return type is part of the method signature as anyone who has experienced an AbstractMethodError can tell you.
Consider however how allowing such overloading might work in tandem with sub-typing:
class A {
def foo: Int = 1
}
val a: A = //...lookup an A
val b = a.foo
This is perfectly valid code of course and javac would uniquely resolve the method call. But what if I subclass A as follows:
class B extends A {
def foo: String = "Hello"
}
This causes the original code's resolution of which method is being called to be broken. What should b be? I have logically broken some existing code by subtyping some existing class, even though I have not changed either that code or that class.
The main reason is complexity issues: with a "normal" compiler approach, you go inside-out (from the inner expression to the outer scope), building your binary step by step; if you add return-type-only differentiation, you need to change to a backtracking approach, which greatly increases compile time, compiler complexity (= bugs!).
Also, if you return a subtype or a type that can be automatically converted to the other, which method should you choose? You'd give ambiguity errors for perfectly valid code.
Not worth the trouble.
All in all, you can easily refactor your code to avoid return-type-only overload, for example by adding a dummy parameter of the type you want to return.
I've never used scala, so someone whack me on the head if I'm wrong here, but this is my take.
Say you have two methods whose signatures differ only by return type.
If you're calling that method, how does the compiler (interpreter?) know which method you actually want to be calling?
I'm sure in some situations it might be able to figure it out, but what if, for example, one of your return types is a subclass of the other? It's not always easy.
Java doesn't allow overloading of return types, and since scala is built on the java JVM, it's probably just a java limitation.
(Edit)
Note that Covariant returns are a different issue. When overriding a method, you can choose to return a subclass of the class you're supposed to be returning, but cannot choose an unrelated class to return.
In order to differentiate between different function with the same name and argument types, but different return types, some syntax is required, or analysis of the site of an expression.
Scala is an expression oriented language (every statement is an expression). Generally expression oriented languages prefer to have the semantics of expressions to be dependent only on the scope evaluation occurs in, not what happens to the result, so for the expression foo() in i_take_an_int( foo() ) and i_take_any_type ( foo()) and foo() as a statement all call the same version of foo().
There's also the issue that adding overloading by return type to a language with type inference will make the code completely incomprehensible - you'd have to keep an incredible amount of the system in mind in order to predict what will happen when code gets executed.
All answers that say the JVM does not allow this are straight up wrong. You can overload based on return type. Surprisingly, the JVM does allow this; it's the compilers for languages that run on the JVM that don't allow this. But there are ways to get around compiler limitations in Scala.
For example, consider the following snippet of code:
object Overload{
def foo(xs: String*) = "foo"
def foo(xs: Int*) = "bar"
}
This will throw a compiler error (Because varargs, indicated by the * after the argument type, type erase to Seq):
Error:(217, 11) double definition:
def foo(xs: String*): String at line 216 and
def foo(xs: Any*): String at line 217
have same type after erasure: (xs: Seq)String
def foo(xs: Any*) = "bar";
However, if you change value of the second foo to 3 instead of bar (that way changing the return type from String to Int) as follows:
object Overload{
def foo(xs: String*) = "foo"
def foo(xs: Int*) = 3
}
... you won't get a compiler error.
So you can do something like this:
val x: String = Overload.foo()
val y: Int = Overload.foo()
println(x)
println(y)
And it will print out:
3
foo
However, the caveat to this method is having to add varargs as the last (or only) argument for the overloaded functions, each with with their own distinct type.
Source: http://www.drmaciver.com/2008/08/a-curious-fact-about-overloading-in-scala/