Thank you, Philipp ! 12:00 important info that is sealed class could be only one of the states you declared, but in data class you can use to define stated that could happen in one time and also declare there states in sealed classes if u need behavior of sealed that I said above
tysm !! I was looking for the best tutorial for sealed classes and here it goes :) !! u r bringing smiles to android dev's crazy life !! Thanks a ton, buddy !!
Thanks for this! After watching this video I realized I had written several classes using enums that would be better off as sealed classes. It's a huge improvement.
Why are you not using polymorphism to render the UI elements if the state has an error? Basically, you could replace the “when” statement with a function in the specific UiState.Error and make it even easier to read
What is the thought for naming the Success/Fail data wrapper "Resource"? I see this similar technique with the same name (Resource) in other blogs and tutorials. "Result" seems a more intuitive name - but I see that Kotlin already has a built-in type class called "Result" with a very similar structure as the "Resource" code. Why not use the built-in Result and why name this Resource?
I had the same thought/question :) though perhaps Phillipp was adding this (new) class for the sake of the example? (and "Resource" kinda also makes sense... in HTTP parlance... i.e. "get/post/put/delete a resource"? :))
thanks. but when get data from API to data class response, how can the field knows which object sealed class to use? for example, json response { name: 'Khalifa', gender: 'male' } with our sealed class Gender { Male, Female } is it automatically serialize base the object name?
With sealed classes when-expressions are nicer because they remind you when you're missing a class in the when expression. But yea, enum classes work as well, I just like sealed classes more as I said in the video
Hey Phillip! one of your biggest fans, Ali from Pakistan here.. Can you please make a video on how do you debug network requests. Like in most of your videos you tell us how to get error or success responses easily from a request but what if I want to look at request body how can I do that with this Resource sealed class design pattern.. Thanks in advance bro 💓
hi Philipp, thank you the nice tutorial, I'm struggling with BaseActivity, BaseFragment, BaseViewModel and Almost every thing with prefix Base, Struggling to understand and write code in internship for my organization, 🙏 please make a video to clear this Base Prefix.
The general problem of teaching to a language capability nowadays is providing a cookbook approach. I will show you how to use sealed classes. Oh, cool. Imagine we have a car class and... Okay, why do not show it in a different way. Show class of problems sealed classes can help you to solve.
What if there are multiple error type at the same time (e.g network error & input empty) to be displayed on ui? should i add it into variable in uistate data class only without Error sealed class or my question just too dumb to be asked? ^^
Thanks as always for the video, Philipp. However, you didn't really explain exactly what (and why/when) sealed classes are used; as compared to regular classes or enums. Apparently, they are "sealed from extension" -- though I've never really understood why this is considered a "good thing". :) Perhaps you could cover/explain that in a followup video?
"sealed from extension" means that a sealed class like Car only has the possible subclasses (like Audi, Bmw, Mercedes) defined by you in your files. other people or files cannot make their own cars: the class is sealed. this is good because it allows the compiler to know that the subclasses it sees are the only ones that exist. for example, if you have a function taking a Car, you can use the when(){} operator and handle Audi, Bmw, and Mercedes only -- there's no need for an unecessary "else ->" branch, like there would be with regular classes, because with a sealed class kotlin knows exactly what type of cars exist, while with a regular class someone could make their own type of Car and call your function with it. enums and sealed classes/interfaces are similar: they are both useful for declaring possible "states" a value could have. for example, a DayOfWeek enum/sealed class would contain monday, tuesday, wednesday, etc. -- enums and sealed classes would both be suitable for making DayOfWeek. however, say you wanted a Vowel enum/sealed class, containing A, E, I, O, and U as possible states. for this to be useful, you might also want to store each vowel's character value, so you can easily make functions that can easily access the character of a Vowel passed into them. this is what enum classes are useful for: enum class Vowel(val character: Char) { A('A') } above, A('A') is a shorthand for A = Vowel('A'): in an enum, states are all instances of the enum class. therefore, Vowel.A is an instance of Vowel and Vowel.A.character is 'A'. keep in mind that every enum instance is of the exact same type, in this case Vowel. it wouldn't be possible to create a Vowel called Y and give it an isAlwaysVowel value of false without giving an isAlwaysVowel values to A, E, I, O, and U too. for this example, regular enums make sense. but imagine you wanted a good way to represent the result of a divide(a: Double, b: Double) function that returns a/b. this seems simple until you remember that you cant divide by zero... so then what? if b is 0 should you just throw an error? with sealed interfaces you can avoid this. think in terms of states. the possible result of the divide() function can have either a success or error state. if the result is a success, it should also have a number associated with it. it's not possible to do this with a regular enum, because with enums you can't say "vowel A should have some character associated with it" -- you can only say "vowel A should have 'A' associated with it". enum states are constants, not types. but in a sealed class/interface, the possible states are classes. for example, you could make a sealed class DivisionResult with states of Success and DivideByZeroError. the error is a singleton and Success is a class that has a num attribute. sealed interface DivisionResult { class Success(val num: Double) : DivisionResult object DivideByZeroError : DivisionResult } these both inherit from DivisionResult, and since DivisionResult is sealed, the compiler knows that a variable of type DivisionResult is always going to be either a DivideByZeroError or a Success (with a number associated). say you have "val x = DivisionResult.Success(1.1)". here, x is an instance of DivisionResult.Success, which inherits from DivisionResult. x.num is 1.1. the best way to think about the difference between enums and sealed classes is that an enum is really a collection of constants with values pre-assigned, while a sealed class heirarchy is a collection of types with their own shapes and values.
Philip, thank you for the lessons! Please answer, is it possible to include subtitles with translation into other languages in the videos on your paid courses? On RUclips, I watch them exactly like this:)
when you don't know yet what type of resource a specific resource is, you can access its data/message. That doesn't work if you only put that in the subclass constructors
@@PhilippLackner if you define an constructor in sealed class, every child has to define this attribute. for instance, if you know that each element of sealed class has an specific attribute, you don't neet to check if an object is of a specific type to access his attribute. sealed class Job(name: String){ object Guardian : Job("guardian") object Cop: Job("cop") } imagine that you have an list of elements of Job, and you want to render the name of each one. You can do it like this: listOf(Job.Cop, Job.Guardian).forEach{ job -> println(job.name) } now imagine that the attributes belongs for each child of Job. sealed class Job{ data class Guardian(name: String) : Job() data class Cop(name: String): Job() } To print the name of each one, you ll need to verify the type to assure that the current object is an specific type, to access his attribute. listOf(Job.Guardian("guardian"), Job.Cop("cop")).forEach{ job -> when(job){ is Cop -> println(job.name) is Guardian -> println(job.name) }
Hey Philip, why not use a single class to pass the resource from the repository to the viewmodel and to the view? Why do we have two different classes i.e. UiState and Resource
1. The resource class is responsible for carrying the result of the API response. The repository does not have the purpose of deciding what the UI sees. If you hardcode that into your repository, you can only use it with one view model and one screen. 2. Enum works as well, but using a sealed class is better to distinguish between errors in a when expression because the compiler knows of all the options and won't complain that there is no else branch
That's a brilliant insight my man. Also the first one, I think you didn't get my point, I was saying that you can have a same class across the Repository and Viewmodel to depict state. I mean I do it for my projects so what's the difference between having a UiState and Resource differently because both have to convey state right?
Great video thank you, it's much clearer now! One question though regarding the data on a Success: even though the "data" parameter for Success is non-nullable "T", it will still accept null as an input, and then down the line, in the "when" block where I'm checking for "is Resource.Success"... Then I need to follow it up with a check to see if the data is not null. Is there a way around? Thanks!!! when (trackResult) { is Resource.Success -> { if (trackResult.data == null || trackResult.data.component1() == null) throw IllegalStateException("Resource.Success should not have null data") val trackInfo = JSONObject( String(trackResult.data.component1()!!) ) track = trackInfo.createTrackFromJson() } is Resource.Error -> {} }
If I recall correctly, he doesn't use a question mark to allow null values in case of success, compared to Resource.Error which does optionally take data that is nullable. In other words, there will never be a null value in case of success because you simply could not create an instance of Resource.Success with a null value. Of course if you wanted that, you could always change it so that it could accept null values (but I think an empty list is better than null).
In Google testing repo I finded next code. Mayby this helpig out. sealed class Result { data class Success(val data: T) : Result() data class Error(val exception: Exception) : Result() object Loading : Result() override fun toString(): String { return when (this) { is Success -> "Success[data=$data]" is Error -> "Error[exception=$exception]" Loading -> "Loading" } } } val Result.succeeded get() = this is Result.Success && data != null // useed data for class Result will available only in next block code if (usersResult is Success) { saveInDatabase(usersResult.data) }
Not sure how useful sealed interfaces would be if ultimately you must also create a sealed class that uses it, and you would have to with this particular usage. Could still be useful for other applications I'm sure.
Great video and thank you for the explanation of sealed class. It's not clear for me as an web-developer (maybe it's android specific) why we don't use emum instead of sealed class in all these examples. These classes don't have any logic inside so how it would be better than enum. And the second point, as I know switch with type check can be replaced with method like getMessage in the sealed class and implementation of it in each type of error. In this case I don't see a reason to make it sealed and close this hierarchy for extension hence every error has to implement this method and will work without main activity changes.
The use of enum classes in Android is discouraged as it mostly requires twice as much memory, which is limited in Android. The usage of sealed classes allows to write more future-proof code as each subclass can have their own implementations while an enum class will have to define the same variables and functions for each enum constant. Whenever you need an additional single function, you don't have to define it everywhere with sealed classes. An enum class exists as an object which means it can only have a single instance when you use values, while a sealed class allows multiple with their own state. For the when statement, you mostly want to keep the specific implementation outside of the sealed class to make it reusable and allow a different implementation based on where you need the class. If you need a variable in all subclasses, you can still define it in the sealed class constructor itself. Extending sealed classes defies its purpose as it represents a restricted hierarchy known at compile-time. Using a when statement for this allows you to use the classes without casting them.
I was really struggling to understand sealed classes, but now I can even explain to someone else after watching the video. Thanks Phillip
16:50 "I don't know, there are so many now a days" 😂😂
Thank you, Philipp ! 12:00 important info that is sealed class could be only one of the states you declared, but in data class you can use to define stated that could happen in one time and also declare there states in sealed classes if u need behavior of sealed that I said above
OMG, you made the video on topic I requested in one of your recent videos.
Thank You Philipp 😊
Enum classes limit instantiation. Sealed classes limit inheritance.
Most importantly enums have a larger footprint, Avoid as much as we can instead use annotations (typedef int) !!
@@bjugdbjk that’s not true any more, i would advice you to look into ART (Android runtime) vs DVM
I just today wanted to learn about sealed classes and here you are.
I am always happy to be welcomed back to your new video 🤓
8:49 you're wild for that LOL
tysm !! I was looking for the best tutorial for sealed classes and here it goes :) !! u r bringing smiles to android dev's crazy life !! Thanks a ton, buddy !!
I always wait for your new videos. thank you so much. i love it!
Thanks!
Very cool video
I don't use sealed classes usually put after this video i will use it more
Thank you Bro
I wish you all the best
I was not using them because I was not understanding them clearly. And, that is over now. Thanks Phil.... :)
I thought that I knew the use of sealed class. But it went wrong after this video 🤭🤭
Thank you Philipp
bro put mia khalifa in at 8:49 😭
Thanks for this! After watching this video I realized I had written several classes using enums that would be better off as sealed classes. It's a huge improvement.
Why are you not using polymorphism to render the UI elements if the state has an error? Basically, you could replace the “when” statement with a function in the specific UiState.Error and make it even easier to read
Can you give an example?
What is the thought for naming the Success/Fail data wrapper "Resource"? I see this similar technique with the same name (Resource) in other blogs and tutorials. "Result" seems a more intuitive name - but I see that Kotlin already has a built-in type class called "Result" with a very similar structure as the "Resource" code. Why not use the built-in Result and why name this Resource?
I had the same thought/question :) though perhaps Phillipp was adding this (new) class for the sake of the example? (and "Resource" kinda also makes sense... in HTTP parlance... i.e. "get/post/put/delete a resource"? :))
thanks. but when get data from API to data class response, how can the field knows which object sealed class to use?
for example, json response { name: 'Khalifa', gender: 'male' } with our sealed class Gender { Male, Female }
is it automatically serialize base the object name?
I have the same doubt. Philip could you please explain this?
Excelent explanation! Good job!
thanks!
No one's going to mention the names he's returning in the person service?
At 17:00 , why to use sealed classes instead of enum class? i mean Gender class could be enum like:
enum class Gender{ Male, Female }
With sealed classes when-expressions are nicer because they remind you when you're missing a class in the when expression. But yea, enum classes work as well, I just like sealed classes more as I said in the video
Very well explained!
I'm confused... in the last example (about genders), why use a sealed class instead of an enum?
Really good videos Philipp
Thanks!
But why not to use enum in example with Gender? It should be more concise.
I use it to listen to distinguish between Loading, Success and Failure states using when via collecting the flow as State :)
Hey Phillip! one of your biggest fans, Ali from Pakistan here..
Can you please make a video on how do you debug network requests.
Like in most of your videos you tell us how to get error or success responses easily from a request but what if I want to look at request body how can I do that with this Resource sealed class design pattern..
Thanks in advance bro 💓
so There will be one uiState Class for each Activity?
thankx philip , super
hi Philipp, thank you the nice tutorial, I'm struggling with BaseActivity, BaseFragment, BaseViewModel and Almost every thing with prefix Base, Struggling to understand and write code in internship for my organization, 🙏 please make a video to clear this Base Prefix.
Am I the only one who saw Mia Khalifa in the list of persons at 8:58? xD On a serious note, thank you for these content Phillip. :)
The general problem of teaching to a language capability nowadays is providing a cookbook approach. I will show you how to use sealed classes. Oh, cool. Imagine we have a car class and... Okay, why do not show it in a different way. Show class of problems sealed classes can help you to solve.
Hey, talk about sealed class vs sealed interface
Bravo! learnt something unexpected
Nice 👌
hey philipp, thanks for this video, i have a question, can we use interface instead of sealed class and if we can't why?
just for info, Kotlin is not an Android only language, and sealed classes exist in java as well.
For Android, java does not support sealed classes
@@PhilippLackner insteresting. isn't java supposed to be Write Once Run Anywhere?
What if there are multiple error type at the same time (e.g network error & input empty) to be displayed on ui? should i add it into variable in uistate data class only without Error sealed class or my question just too dumb to be asked? ^^
Thanks as always for the video, Philipp. However, you didn't really explain exactly what (and why/when) sealed classes are used; as compared to regular classes or enums. Apparently, they are "sealed from extension" -- though I've never really understood why this is considered a "good thing". :) Perhaps you could cover/explain that in a followup video?
"sealed from extension" means that a sealed class like Car only has the possible subclasses (like Audi, Bmw, Mercedes) defined by you in your files. other people or files cannot make their own cars: the class is sealed.
this is good because it allows the compiler to know that the subclasses it sees are the only ones that exist. for example, if you have a function taking a Car, you can use the when(){} operator and handle Audi, Bmw, and Mercedes only -- there's no need for an unecessary "else ->" branch, like there would be with regular classes, because with a sealed class kotlin knows exactly what type of cars exist, while with a regular class someone could make their own type of Car and call your function with it.
enums and sealed classes/interfaces are similar: they are both useful for declaring possible "states" a value could have. for example, a DayOfWeek enum/sealed class would contain monday, tuesday, wednesday, etc. -- enums and sealed classes would both be suitable for making DayOfWeek.
however, say you wanted a Vowel enum/sealed class, containing A, E, I, O, and U as possible states. for this to be useful, you might also want to store each vowel's character value, so you can easily make functions that can easily access the character of a Vowel passed into them. this is what enum classes are useful for:
enum class Vowel(val character: Char) {
A('A')
}
above, A('A') is a shorthand for A = Vowel('A'): in an enum, states are all instances of the enum class. therefore, Vowel.A is an instance of Vowel and Vowel.A.character is 'A'. keep in mind that every enum instance is of the exact same type, in this case Vowel. it wouldn't be possible to create a Vowel called Y and give it an isAlwaysVowel value of false without giving an isAlwaysVowel values to A, E, I, O, and U too. for this example, regular enums make sense.
but imagine you wanted a good way to represent the result of a divide(a: Double, b: Double) function that returns a/b. this seems simple until you remember that you cant divide by zero... so then what? if b is 0 should you just throw an error? with sealed interfaces you can avoid this. think in terms of states. the possible result of the divide() function can have either a success or error state. if the result is a success, it should also have a number associated with it.
it's not possible to do this with a regular enum, because with enums you can't say "vowel A should have some character associated with it" -- you can only say "vowel A should have 'A' associated with it". enum states are constants, not types. but in a sealed class/interface, the possible states are classes. for example, you could make a sealed class DivisionResult with states of Success and DivideByZeroError. the error is a singleton and Success is a class that has a num attribute.
sealed interface DivisionResult {
class Success(val num: Double) : DivisionResult
object DivideByZeroError : DivisionResult
}
these both inherit from DivisionResult, and since DivisionResult is sealed, the compiler knows that a variable of type DivisionResult is always going to be either a DivideByZeroError or a Success (with a number associated). say you have "val x = DivisionResult.Success(1.1)". here, x is an instance of DivisionResult.Success, which inherits from DivisionResult. x.num is 1.1.
the best way to think about the difference between enums and sealed classes is that an enum is really a collection of constants with values pre-assigned, while a sealed class heirarchy is a collection of types with their own shapes and values.
8:50 Mia khalifa 😂😂
Where do I get the source code for this tutorial?
Thanks my friend, this video was awesome,
but why you used that names for the person list?
do you like them?
XD
Kindly explain about in and out keywords in kotlin.
Philip, thank you for the lessons! Please answer, is it possible to include subtitles with translation into other languages in the videos on your paid courses? On RUclips, I watch them exactly like this:)
Having auto-generated subtitles on Vimeo is incredibly expensive sadly
Dude you saved me 😍
Haven't watched yet but I already know it's a thumbs up
Thank you!
Sir what is extension funcation?
Why do we need a constructor in Resource sealed class while we can declare variables in those sub-classes?
when you don't know yet what type of resource a specific resource is, you can access its data/message. That doesn't work if you only put that in the subclass constructors
@@PhilippLackner if you define an constructor in sealed class, every child has to define this attribute.
for instance, if you know that each element of sealed class has an specific attribute, you don't neet to check if an object is of a specific type to access his attribute.
sealed class Job(name: String){
object Guardian : Job("guardian")
object Cop: Job("cop")
}
imagine that you have an list of elements of Job, and you want to render the name of each one. You can do it like this:
listOf(Job.Cop, Job.Guardian).forEach{ job ->
println(job.name)
}
now imagine that the attributes belongs for each child of Job.
sealed class Job{
data class Guardian(name: String) : Job()
data class Cop(name: String): Job()
}
To print the name of each one, you ll need to verify the type to assure that the current object is an specific type, to access his attribute.
listOf(Job.Guardian("guardian"), Job.Cop("cop")).forEach{ job ->
when(job){
is Cop -> println(job.name)
is Guardian -> println(job.name)
}
Hey Philip, why not use a single class to pass the resource from the repository to the viewmodel and to the view? Why do we have two different classes i.e. UiState and Resource
Also we could have Error as an enum rather than a sealed class because we just simply want a countable list of stuff
1. The resource class is responsible for carrying the result of the API response. The repository does not have the purpose of deciding what the UI sees. If you hardcode that into your repository, you can only use it with one view model and one screen.
2. Enum works as well, but using a sealed class is better to distinguish between errors in a when expression because the compiler knows of all the options and won't complain that there is no else branch
That's a brilliant insight my man. Also the first one, I think you didn't get my point, I was saying that you can have a same class across the Repository and Viewmodel to depict state. I mean I do it for my projects so what's the difference between having a UiState and Resource differently because both have to convey state right?
@@gauravthakkar802 Can you provide your sample code here ? or share link of gist.
Legend!
Great video thank you, it's much clearer now! One question though regarding the data on a Success:
even though the "data" parameter for Success is non-nullable "T", it will still accept null as an input, and then down the line, in the "when" block where I'm checking for "is Resource.Success"... Then I need to follow it up with a check to see if the data is not null. Is there a way around? Thanks!!!
when (trackResult) {
is Resource.Success -> {
if (trackResult.data == null || trackResult.data.component1() == null)
throw IllegalStateException("Resource.Success should not have null data")
val trackInfo = JSONObject(
String(trackResult.data.component1()!!)
)
track = trackInfo.createTrackFromJson()
}
is Resource.Error -> {}
}
you could by making changing the data of the success resource to a val and renaming it, but then you have two datas which is kinda confusing
If I recall correctly, he doesn't use a question mark to allow null values in case of success, compared to Resource.Error which does optionally take data that is nullable. In other words, there will never be a null value in case of success because you simply could not create an instance of Resource.Success with a null value. Of course if you wanted that, you could always change it so that it could accept null values (but I think an empty list is better than null).
In Google testing repo I finded next code. Mayby this helpig out.
sealed class Result {
data class Success(val data: T) : Result()
data class Error(val exception: Exception) : Result()
object Loading : Result()
override fun toString(): String {
return when (this) {
is Success -> "Success[data=$data]"
is Error -> "Error[exception=$exception]"
Loading -> "Loading"
}
}
}
val Result.succeeded
get() = this is Result.Success && data != null
// useed
data for class Result will available only in next block code
if (usersResult is Success) {
saveInDatabase(usersResult.data)
}
Have you considered using sealed interfaces instead?
Not sure how useful sealed interfaces would be if ultimately you must also create a sealed class that uses it, and you would have to with this particular usage. Could still be useful for other applications I'm sure.
Mia Khalifa and a multi gender talk in the same video.
You are wild bro haha
As always great content
Great video and thank you for the explanation of sealed class. It's not clear for me as an web-developer (maybe it's android specific) why we don't use emum instead of sealed class in all these examples. These classes don't have any logic inside so how it would be better than enum. And the second point, as I know switch with type check can be replaced with method like getMessage in the sealed class and implementation of it in each type of error. In this case I don't see a reason to make it sealed and close this hierarchy for extension hence every error has to implement this method and will work without main activity changes.
The use of enum classes in Android is discouraged as it mostly requires twice as much memory, which is limited in Android. The usage of sealed classes allows to write more future-proof code as each subclass can have their own implementations while an enum class will have to define the same variables and functions for each enum constant. Whenever you need an additional single function, you don't have to define it everywhere with sealed classes. An enum class exists as an object which means it can only have a single instance when you use values, while a sealed class allows multiple with their own state. For the when statement, you mostly want to keep the specific implementation outside of the sealed class to make it reusable and allow a different implementation based on where you need the class. If you need a variable in all subclasses, you can still define it in the sealed class constructor itself. Extending sealed classes defies its purpose as it represents a restricted hierarchy known at compile-time. Using a when statement for this allows you to use the classes without casting them.
Philipp? Is it really the right repository in description? There is no sealed class.
Oh thanks for telling me it was wrong. I don't have a repository for this video
thanks fleep
Continuous jet pack compose playlists
that Moment i saw a person name of "Mia Khalifa"
timestamp??
@@maskedredstonerproz 8:50
@@rushlive thanks
Mia who?
Thank you for this 🙇♂️🙇♂️🙇♂️
Can you say in your next video..."Jennifer poops at parties?" 🤪😉😘
16:52 talking about tiktok guys nowadays they are on the instagram cool 😂🤣
how to fix this Warning: Mapping new ns thanks sir
Dude, the little easter eggs are so funny! Mia Khalifa ^^
These are called "Sum types", part of "Algebraic Data Types". By the way, your "Resource" type looks a lot like the "Either" type
Is it only me who spotted “Mia khlifa “ name at 08:46. 😂
✌
Very good, it has not to be a BOOLEAN to be a BOOLEAN.
Enum class on steroids 🤣
you are very handsome your content is also amazing
Sir sir. Who is Mia Khalifa??🤣
Mia who?
Thought I was the first one..
Appy coding!
Mia Khalifa 😅 What an example bro 😛
*As a java android developer i see Kotlin is worst language with weird syntax and weird new things*
As tetris Player I see call of duty as worst game with weird graphics and weird new things
@@PhilippLackner *You look like henry cavill*
Mia Khalifa 😆
mia khalifa
This is just bad
why?
Thank you!