Nico
05/08/2020, 12:21 PMDerek Peirce
05/08/2020, 4:49 PMtrue
for (None, None)
, and your Jake Wharton example ignores the "Someone else's" case.Nico
05/08/2020, 4:55 PMMarc Knaup
05/08/2020, 7:11 PMis (addr, true)
is confusing as the latter is not a type.
What about simply (addr, true)
?
Note that (1, 2) -> ā¦
would throw in component2()
when matching against listOf(1)
. Iām not sure that this would be intended.Marc Knaup
05/08/2020, 7:14 PMis Closed(valueException) -> throw valueException
is State<*>(UNDEFINED) -> throw IllegalStateException("No value")
is State<*>(value) -> return value as E
else -> error("Invalid state $state)
This wonāt work. The compiler would have to guess whether you want to pass a value for matching (like UNDEFINED
) or you want to define a variable (like valueException
). The latter should need a val
.
Then again I donāt see much benefit in destructuring into new variables here since the smart cast already makes it very easy (state.valueException
).Marc Knaup
05/08/2020, 7:18 PMNico
05/08/2020, 7:31 PMis (_, true)
. At the same time, I thought it would be appropriate if in order to pattern match the keyword is
was necessary. Having (a, b)
directly looks as if we were calling (a, b) == subject
(which is what would happen if instead of that tuple we had anything else). I personally prefer is
but I will add your alternative to the proposal see what people likeNico
05/08/2020, 7:32 PMUNDEFINED
example, I don't see the problem. It is an identifier like any other, and seeing it's already present in scope should tell apart one case from the otherNico
05/08/2020, 7:33 PMMarc Knaup
05/08/2020, 7:36 PMis
. Itās used exclusively for instance checks, whether in when matching or otherwise and I think itās better if it stays that way šMarc Knaup
05/08/2020, 7:37 PMHavingĀI donāt know what you mean here. There is no call and it doesnāt look like one either. Itās perfectly in sync with destructuring, and most other languages :)directly looks as if we were callingĀ(a, b)
(a, b) == subject
Marc Knaup
05/08/2020, 7:39 PMAs for theĀ UNDEFINEDĀ example, I donāt see the problem. It is an identifier like any other, and seeing itās already present in scope should tell apart one case from the otherThat would be a very big source of errors. Just mistyping a variable name and instead of providing a value you create a new variable. It doesnāt make sense for a static language like Kotlin. āIf variable exists then use value else create new variableā š Sounds more like something that PHP would do (wrong).
Nico
05/08/2020, 7:40 PMis
, but all current matching does is call equals()
on subject and target. Whether here the semantics on some (a, b)
as a target are different and I thought it would be important to differentiate that. But then again, using is
has exactly the same problem so that's a fair point!Nico
05/08/2020, 7:41 PMMarc Knaup
05/08/2020, 7:41 PMequals
for both anyway?Marc Knaup
05/08/2020, 7:43 PMNico
05/08/2020, 7:46 PMequals
for those already defined, but would recursively pattern match otherwise. Consider (3, Person("Alice"))
. Here you are doing a type check in the pattern but there is no is
. And we cannot fully remove is
for non nested patterns because we cannot pattern match on Person("Alice")
as that is creating a new Person
and calling equals on it (which may have different semantics from componentN()
, aside from extra overhead.Nico
05/08/2020, 7:48 PMMarc Knaup
05/08/2020, 7:50 PMMarc Knaup
05/08/2020, 7:53 PMPerson("Alice", _)
but not Person("Alice")
, the latter which can be ambiguous and confusing.
⢠The same goes for partial matching of desctructuring.
Will (1)
match listOf(1)
and listOf(1, 2)
or just the former? I think most languages would only match the first case and you cannot do that with only componentN()
functions.Nico
05/08/2020, 7:53 PMMarc Knaup
05/08/2020, 7:53 PMNico
05/08/2020, 7:54 PMMarc Knaup
05/08/2020, 7:54 PMPerson("Alice", _)
can indeed not use equals
of a data class, which would break existing code when not using wildcards, because in that case equals
is currently used.Marc Knaup
05/08/2020, 7:56 PMis
only makes sense when the type isnāt checked yet.
val person: Person = ā¦
when (person) {
is Person -> ā¦
}
That would be an unnecessary instance check already and yield a warning.Nico
05/08/2020, 7:56 PMcomponentN()
functions. You cannot enforce matching on every single componentN
for data classes but not for lists. Again, I think the expected behaviour of destructuring in a pattern match should be as close as possible to the destructuring already present in the language.
Currently, writing val (name) = Person("Alice")
is valid so I do not see a problem with carrying that over to the KEEPMarc Knaup
05/08/2020, 7:57 PMis Person("Alice", _)
is two things in one:
is Person
and matching the first componentNico
05/08/2020, 7:59 PMMarc Knaup
05/08/2020, 7:59 PMwhen (listOf(1, 2)) {
(1) -> ⦠// (1) unexpectedly matches (1, 2) - Tuples and Lists are very similar and it can easily lead to confusion.
(1, 2, 3) -> // Expectation would be that it does not match. What actually happens is that an exception is thrown.
}
Nico
05/08/2020, 8:00 PMMarc Knaup
05/08/2020, 8:00 PMNico
05/08/2020, 8:00 PMval (a, b, c) = listOf(1, 2)
compiles but throws a runtime exceptionNico
05/08/2020, 8:00 PMNico
05/08/2020, 8:01 PMMarc Knaup
05/08/2020, 8:01 PMMarc Knaup
05/08/2020, 8:01 PMis
vs as
Nico
05/08/2020, 8:02 PMcomponentN
exists. We could give lists special treatment to fail a match depending on their size, I can agree with thatMarc Knaup
05/08/2020, 8:03 PMcomponentN
is a very simple construct. Whether or not it throws depends on the case and List
is just one example. not an edge case.Marc Knaup
05/08/2020, 8:03 PMNico
05/08/2020, 8:03 PMMarc Knaup
05/08/2020, 8:04 PMNico
05/08/2020, 8:04 PMcomponentN
to fail for collectionsMarc Knaup
05/08/2020, 8:04 PMNico
05/08/2020, 8:04 PMNico
05/08/2020, 8:04 PMNico
05/08/2020, 8:04 PMNico
05/08/2020, 8:05 PMMarc Knaup
05/08/2020, 8:05 PMList
instead of generically for componentN
what youāre aiming for.Marc Knaup
05/08/2020, 8:06 PMcomponentCount()
^^Nico
05/08/2020, 8:06 PMMarc Knaup
05/08/2020, 8:06 PMMarc Knaup
05/08/2020, 8:06 PMcomponentN
for everything. Including throwing if destructing doesnāt make sense.Nico
05/08/2020, 8:06 PMMarc Knaup
05/08/2020, 8:07 PMNico
05/08/2020, 8:07 PMMarc Knaup
05/08/2020, 8:07 PMNico
05/08/2020, 8:08 PMcomponentN
to enable matching on them. I am thinking in particular of Java classes that users might want to extend to use more idiomatically in KotlinNico
05/08/2020, 8:09 PMMarc Knaup
05/08/2020, 8:09 PMMarc Knaup
05/08/2020, 8:10 PMNico
05/08/2020, 8:10 PMMarc Knaup
05/08/2020, 8:10 PMMarc Knaup
05/08/2020, 8:10 PMNico
05/08/2020, 8:11 PMNico
05/08/2020, 8:11 PMNico
05/08/2020, 8:11 PMMarc Knaup
05/08/2020, 8:11 PMMarc Knaup
05/08/2020, 8:12 PMMarc Knaup
05/08/2020, 8:13 PMPerson("Alice", true)
and Person("Alice", _)
could work totally different than expected if a custom equals
was provided, because itās ignored when a wildcard is used.Nico
05/08/2020, 8:13 PMcomponentN
functions?Marc Knaup
05/08/2020, 8:14 PMcomponentN
is necessary as the compiler knows what parameter is at what position.Nico
05/08/2020, 8:14 PMis
. In that case we only call equals
on "Alice" and true
, not on Person(..) itselfMarc Knaup
05/08/2020, 8:15 PMPerson(āAliceā, true)Ā andĀ Person(āAliceā, _)Ā could work totally different than expected if a customĀ equalsĀ was provided, because itās ignored when a wildcard is used.Another one: The former would call the/a constructor while the latter wonāt.
Marc Knaup
05/08/2020, 8:15 PMis
then but something else. is
is confusing. Itās already a Person
.Nico
05/08/2020, 8:15 PMis Person("Alice", true)
will not create a new aliceNico
05/08/2020, 8:16 PMequals
on membersMarc Knaup
05/08/2020, 8:16 PMis Person(String, Boolean)
would make sense for is
šNico
05/08/2020, 8:17 PMcomponentN
in data classes you are introducing breaking changes if we ever to use it in the future (like for Map.Entry maybe)Marc Knaup
05/08/2020, 8:17 PMlike Person("Alice", true)
?Nico
05/08/2020, 8:17 PMPerson
which is the whole point of pattern matchingMarc Knaup
05/08/2020, 8:17 PMMarc Knaup
05/08/2020, 8:17 PMMarc Knaup
05/08/2020, 8:18 PMPerson(x, y)
is data class, otherwise you wouldnāt write Person
Nico
05/08/2020, 8:18 PMMarc Knaup
05/08/2020, 8:18 PMMap.Entry(a, b)
but (a, b)
which can happily use componentX
Marc Knaup
05/08/2020, 8:18 PMPerson
Nico
05/08/2020, 8:18 PMis
check succeedsNico
05/08/2020, 8:19 PMNico
05/08/2020, 8:20 PMMarc Knaup
05/08/2020, 8:22 PMMarc Knaup
05/08/2020, 8:25 PMval result = when(download) {
is App(name, Person("Alice", _)) -> "Alice's app $name"
is Movie(title, Person("Alice", _)) -> "Alice's movie $title"
is App, Movie -> "Not by Alice"
}
For example could also be written like this:
val result = when(download) {
is App where download.developer.name == "Alice" -> "Alice's app ${download.name}"
is Movie where download.developer.name == "Alice" -> "Alice's movie ${download.title}"
is App, is Movie -> "Not by Alice"
}
Thatās closer to what we have today and avoids the problem with data classes and destructuing for now, yet vastly improves such use cases already.Marc Knaup
05/08/2020, 8:28 PMWithout pattern matching
example for that case also isnāt ideal and can be improved with todayās Kotlin. It unnecessarily uses destructuring.Marc Knaup
05/08/2020, 8:29 PMAlice
, not the name of the developer.Marc Knaup
05/08/2020, 8:31 PMNico
05/08/2020, 8:53 PMNico
05/08/2020, 8:55 PMNico
05/08/2020, 9:01 PMBen Woodworth
05/08/2020, 9:16 PMcomponentN
)Nico
05/08/2020, 9:20 PMNico
05/08/2020, 9:22 PMBen Woodworth
05/08/2020, 9:40 PM