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 asNico
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 PersonNico
05/08/2020, 8:18 PMMarc Knaup
05/08/2020, 8:18 PMMap.Entry(a, b) but (a, b) which can happily use componentXMarc Knaup
05/08/2020, 8:18 PMPersonNico
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