purescript-react/purescript-react-basic

Why EventFn has no Functor (or Profunctor) instance?

Closed this issue · 4 comments

Why EventFn has no Functor (or Profunctor) instance?
paf31 commented

It would be unsafe to have one. The point is that EventFn behaves like a linear function, but a Functor instance would allow non-linearity to creep in.

Linearity is important so as not to let the synthetic event object leak out of scope.

paluh commented

@paf31 Could you please explain it a bit more? I'm just not sure what do you mean by "scope" here and I don't understand what kind of safety EventFn gives us in this case.
I think that I can use for example identity (or for example preventDefault) to get an access to SyntheticEvent in my handler effect and do whatever I want with SyntaticEvent value there:

handler identity doWhateverYouWant

Probably I'am missing something but it seems to me that if we want to prevent escaping SyntheticEvent value outside handler scope we should probably use phantom type trick in like in ST. Maybe something like:

handler ::  forall a. (forall h. SyntheticEvent h -> a) -> (a -> Effect Unit) -> EventHandler

But probably I don't understand what is going on now and this is bad idea ;-)

“Scope” here is “synchronously in the event handler”. React wraps events in an object they call a “synthetic event”. They become invalid as soon as the event callback JS loop completes (in dev they are simply modified to throw exceptions when accessed, in prod they are overwritten with new event data as the objects get pooled and reused for performance).

It’s true that you can aquire a reference to a SyntheticEvent. The first way is to just not use the EventFn helpers and write your own EventHandler, and the second is the way you already mentioned. That was added as a sort of “necessary evil” because there were cases where a handler would want to read some event properties before deciding whether or not to defer to a second handler, such as one passed in as a prop. In both of these cases it’s up to you to use the SyntheticEvent correctly.

Those are exceptions though. If you stick to the EventFn helpers provided to build a single handler, it’s impossible to do it in a way which uses the SyntheticEvent’s scope incorrectly.

paluh commented

Thanks @spicydonuts!

It is a bit more clear now for me what is the idea behind this specific convention for event handling. I think we are going to experiment with this other approach a bit on our fork too.