I’m curious regarding the naming conventions behin...
# codingconventions
m
I’m curious regarding the naming conventions behind having
toList()
but then
asSequence()
instead of
toSequence()
?
j
Usually in the Kotlin stdlib
asSomething()
implies that the returned
Something
wraps the receiver (or exposes it as a different type), while
toSomething()
implies that the new
Something
will copy everything it needs from the receiver and have no further relation to it.
🙏 2
m
Although in this particular case an iterator on the
asSequence()
vs
toList()
will return the same items. But I suppose it wouldn’t be expected to do a deep copy, so that’s a moot point
j
The difference is that
toList()
will create a new list from the existing one, while
asSequence()
will only bridge the type but still take its items from the original collection. If you were to change the original collection after conversion, the
toList()
variant will not be affected while the
asSequence()
result will show the changes: https://pl.kotl.in/mT9gSB1Uc
👍 2
m
I find it a bit confusing regarding
toCollection(destination)
which kind of uses a very different interpretation of
to
. I suppose it maintains the philosophy of
to
being unaffected by changes to the original
j
It's similar. The items will be inserted into a new independent collection, just like
toList
. The only difference is that you provide the new collection yourself instead of letting the function create it. But I agree the collection will not necessarily be "new' in that case. I find the
as-
prefix pretty neat because it aligns with the casting operator
as
, which is really hinting towards the fact that we express the object as a different type, but it's really the same object behind the scenes.
👍 3
e
yep, the naming convention carries over to the rest of stdlib, although the difference isn't really observable for immutable types, and there aren't many built-in mutable types
👍 1
Copy code
val a = mutableListOf("hello", "world")
val b = a.asReversed()
assert(b == listOf("world", "hello"))
a[0] = "goodbye"
assert(b == listOf("world", "goodbye"))

val c = listOf(1)
val d = c.toIntArray()
assert(d[0] == 1)
c[0] = 2
assert(d[0] == 1)
n
(that should be a
val c = mutableListOf(1)
)
m
On a related note, I guess an implementation like this is bad practice?
Copy code
fun CharSequence.asSpannableStringBuilder() =
    this as? SpannableStringBuilder ?: SpannableStringBuilder(this)
and that we should prefer:
Copy code
fun CharSequence.toSpannableStringBuilder() = SpannableStringBuilder(this)
Either way, you shouldn’t use the original receiver because it contains spans that are now used by the returned object because spans are not allowed to be used in multiple builders.
e
spans should either be copyable between spannables or implement NoCopySpan, so that shouldn't be an issue. the problem with your first function is that it's unclear whether the original receiver will be mutated or not.
m
Oh interesting, I didn’t know about
NoCopySpan
e
this is rather android-specific, but you should consider using or following the precedent of https://developer.android.com/reference/kotlin/androidx/core/text/package-summary#buildSpannedString(kotlin.Function1)
m
Hmm, I normally use that, but good to see how it returns
SpannedString(builder)
rather than the
SpannableStringBuilder
itself, for example as a
CharSequence
On another Android-specific (and non-Kotlin!) note I see that
SpannedString
does:
Copy code
public static SpannedString valueOf(CharSequence source) {
        if (source instanceof SpannedString) {
            return (SpannedString) source;
        } else {
            return new SpannedString(source);
        }
    }
e
SpannedString
is immutable so that's fine
👍 1
m
So yet another reason why
SpannedString
is a better return type than
CharSequence