CLOVIS
06/15/2020, 1:18 PMinterface Event {
val start: ...
val end: ...
val canSubscribe: Boolean
suspend fun subscribe()
}
But that's a lot of boilerplate per feature, and since I want to learn Arrow, I'm thinking there must be a better way.
What do you think of:
interface Event {
val start: ...
val end: ...
fun subsribe(): Either<UnsupportedOperationException, IO<Unit>>
}
pakoito
06/16/2020, 12:27 AMpakoito
06/16/2020, 12:28 AMpakoito
06/16/2020, 12:28 AMpakoito
06/16/2020, 12:34 AMpakoito
06/16/2020, 12:35 AMpakoito
06/16/2020, 12:36 AMsuspend fun subscribe(start, end): Either<UnsupportedOperationException, Unit>
subsume all functionality you need? maybe it needs one or two additional parametersCLOVIS
06/16/2020, 8:18 AMpakoito
06/16/2020, 9:40 AMpakoito
06/16/2020, 9:40 AMpakoito
06/16/2020, 9:41 AMpakoito
06/16/2020, 9:42 AMCLOVIS
06/16/2020, 9:51 AMCLOVIS
06/16/2020, 9:51 AMpakoito
06/16/2020, 3:13 PMpakoito
06/16/2020, 3:13 PMpakoito
06/16/2020, 3:13 PMpakoito
06/16/2020, 3:13 PMpakoito
06/16/2020, 3:14 PMclass Parent {
open fun bla() {
doThing()
}
}
class Child1 {
override fun bla() {
super.bla()
someThing()
}
}
class Child2 {
override fun bla() {
super.bla()
otherThing()
}
}
pakoito
06/16/2020, 3:14 PMpakoito
06/16/2020, 3:16 PMfun bla(f: () -> Unit) {
doThing()
f()
}
...
when (val action = getAction()) {
is Action1 -> bla { action.someThing() }
is Action2 -> bla { action.otherThing() }
}
pakoito
06/16/2020, 3:17 PMbla
can be definedpakoito
06/16/2020, 3:18 PMsuspend fun <A: Serializable, B> bla(before: () -> A, after: (A) -> B): B {
val thing = before()
serialize(thing)
return after(thing)
}
pakoito
06/16/2020, 3:19 PMwhen (val action = getAction()) {
is Action1 -> bla(before = { processAction(action) }, after = { action.someThing(it) })
is Action2 -> bla(before = { action.someField }, after = { action.otherThing(it) })
}
pakoito
06/16/2020, 3:20 PMhandleError
on top of this way of writing codepakoito
06/16/2020, 3:21 PMCLOVIS
06/16/2020, 8:53 PMpakoito
06/16/2020, 10:25 PMpakoito
06/16/2020, 10:25 PMpakoito
06/16/2020, 10:26 PMpakoito
06/16/2020, 10:26 PMpakoito
06/16/2020, 10:26 PMpakoito
06/16/2020, 10:26 PMpakoito
06/16/2020, 10:26 PMpakoito
06/16/2020, 10:27 PMpakoito
06/16/2020, 10:27 PMpakoito
06/16/2020, 10:27 PMpakoito
06/16/2020, 10:27 PMpakoito
06/16/2020, 10:28 PMpakoito
06/16/2020, 10:28 PMpakoito
06/16/2020, 10:28 PMpakoito
06/16/2020, 10:29 PMpakoito
06/16/2020, 10:30 PMpakoito
06/16/2020, 10:31 PMpakoito
06/16/2020, 10:32 PMpakoito
06/16/2020, 10:32 PMpakoito
06/16/2020, 10:33 PMpakoito
06/16/2020, 10:33 PMpakoito
06/16/2020, 10:34 PMCLOVIS
06/17/2020, 8:20 AMinterface Event
interface Priority
interface GoogleMeetConference
interface Notifications
class GoogleEvent : Event, GoogleMeetConference, Notifications
class NextCloudEvent : Event, Priority, Notifications
class AppleEvent : Event
I think it's good because it allows to write a when
to know which functionalities are supported by a particular object, to eg. hide the other options when it's displayed; but it sounds to me like a lot of code, what do you think?pakoito
06/17/2020, 11:04 AMpakoito
06/17/2020, 11:04 AMpakoito
06/17/2020, 11:07 AMEvents can be synced with multiple providers, eg. Google Calendar, NextCloud and Apple Calendar. Google doesn’t support setting a priority, but NextCloud does. Google allows you to create a Google Meet conference, but both others don’t. Google and NextCloud let’s you set notifications, but Apple doesn’t [I’m sure Apple does as well, that’s just for the example].that’s fine, each can do its own thing. What’s telling them what to set? can you make a single mega data class with all this info, then delegate to each implementation to set according to its own capabilities
pakoito
06/17/2020, 11:08 AMpakoito
06/17/2020, 11:13 AMdata class Event(val p: Priority, val c: ConferenceRoom, val n: Notification)
interface EventVisitor<T> {
suspend fun visit(e: Event): T
}
object GoogleEventSave: EventVisitor<Unit> {
suspend fun visit(e: Event): Unit {
GoogleAPI.newEvent().setConference(e.c).submit()
}
}
object NextCloudSave: EventVisitor<Unit> {
suspend fun visit(e: Event): Unit {
NextCloud().makeEvent().setConference(e.c).setPriority(e.p).save()
}
}
pakoito
06/17/2020, 11:14 AMpakoito
06/17/2020, 11:16 AMsuspend fun Event.save(v: EventVisitor<Unit>): Unit = v.visit(this)
pakoito
06/17/2020, 11:16 AMmyEvent.save(GoogleEventSave)
pakoito
06/17/2020, 11:18 AMpakoito
06/17/2020, 11:22 AMpakoito
06/17/2020, 11:25 AM@extension interface SaveEvent<F, T>: EventVisitor<Unit> {
suspend fun visit(e: Event): Unit
suspend fun Event.save(): Unit = visit(this)
}
object GoogleEventSave: SaveEvent<ForGoogle> {
suspend fun visit(e: Event): Unit {
GoogleAPI.newEvent().setConference(e.c).submit()
}
}
object NextCloudSave: SaveEvent<ForNextCloud> {
suspend fun visit(e: Event): Unit {
NextCloud().makeEvent().setConference(e.c).setPriority(e.p).save()
}
}
myEvent.save() // SaveEvent is resolved statically on the method where this line is. Otherwise the method needs to be parametrized for F
CLOVIS
06/17/2020, 7:49 PMCLOVIS
06/17/2020, 9:05 PMCLOVIS
06/17/2020, 9:12 PMCLOVIS
06/17/2020, 9:21 PMobject GooglePriorityProvider: Priority<ForGoogle> {
private val priorities: MutableMap<Event, Int>
var Event.priority by priorities[this]
}
But then, the GoogleEventSave object should know about it to be able to save that information as well?
Is there such a thing as implementing a typeclass as a class
and not an object
, so it can have state linked to the original object? Sorry if this doesn't make sense, typeclasses are not fully clear to my mind, at this point.