Skip to content

Get rid of unsafeCoerce#353

Closed
arybczak wants to merge 3 commits intomasterfrom
no-unsafe-coerce
Closed

Get rid of unsafeCoerce#353
arybczak wants to merge 3 commits intomasterfrom
no-unsafe-coerce

Conversation

@arybczak
Copy link
Copy Markdown
Collaborator

@arybczak arybczak commented Sep 6, 2020

No description provided.

@phadej
Copy link
Copy Markdown
Contributor

phadej commented Sep 6, 2020

The unsafeCoerce can be made nicer, but I think that calculating proofs is justified. (IMHO INCOHERENT instances are about as bad as unsafeCoerce - you have to justify why it's fine to pick either).

@arybczak
Copy link
Copy Markdown
Collaborator Author

arybczak commented Sep 6, 2020

Eh, it looks like there are weird test failures anyway.

@arybczak arybczak force-pushed the no-unsafe-coerce branch 3 times, most recently from d566519 to 6795ea2 Compare September 6, 2020 18:02
@arybczak
Copy link
Copy Markdown
Collaborator Author

arybczak commented Sep 6, 2020

I fixed test failures and made only one instance incoherent.

@arybczak arybczak force-pushed the no-unsafe-coerce branch 2 times, most recently from 5ae1144 to c30d1db Compare September 6, 2020 19:10
@adamgundry
Copy link
Copy Markdown
Member

adamgundry commented Sep 6, 2020

The incoherence seems fine here as there really is only one possible dictionary (modulo bottoms).

I'm less clear about the runtime performance trade-off. Will this all optimize away for nontrivial concrete index lists? I guess it might, even though appendIndices is recursive, because it is polymorphic recursion through a typeclass. And if so, there's no unsafeCoerce to gum up the inliner (EDIT: although of course in the concrete case the unsafeCoerce would be between equal types anyway, so hopefully it disappears regardless?). We could use Tagged instead of a proxy argument to make appendIndices fractionally cheaper if it does end up doing runtime work?

What about type-inference/errors, especially in the case of index-polymorphic code? Of course AppendIndices will show up in inferred types, e.g.:

*Optics.Core> :t (%)
(%)
  :: (Is k (Join k l), Is l (Join k l),
      AppendIndices is js (Append is js)) =>
     Optic k is s t u v
     -> Optic l js u v a b -> Optic (Join k l) (Append is js) s t a b

although we could make this a bit more compact by dropping the third parameter from AppendIndices, since it is entirely determined by the first two anyway.

@arybczak
Copy link
Copy Markdown
Collaborator Author

arybczak commented Sep 7, 2020

I'm less clear about the runtime performance trade-off. Will this all optimize away for nontrivial concrete index lists?

According to my experiments it does. I modified tests so it's also checked there.

We could use Tagged instead of a proxy argument to make appendIndices fractionally cheaper if it does end up doing runtime work?

I modified it to use Proxy# instead.

What about type-inference/errors, especially in the case of index-polymorphic code?

I removed the third argument from the class, the signature looks a bit better now.

λ> :t (%)
(%)
  :: (Is k (Join k l), Is l (Join k l), AppendIndices is js) =>
     Optic k is s t u v
     -> Optic l js u v a b -> Optic (Join k l) (Append is js) s t a b

@arybczak
Copy link
Copy Markdown
Collaborator Author

@adamgundry ping

@arybczak
Copy link
Copy Markdown
Collaborator Author

arybczak commented Sep 13, 2020

Though I'm not 100% sure if it's worth it.

It looks like it's just going to require putting corresponding AppendIndices to the context whenever Append is used with polymorphic indices, though this ought to be internal detail.

@adamgundry
Copy link
Copy Markdown
Member

We could use Tagged instead of a proxy argument to make appendIndices fractionally cheaper if it does end up doing runtime work?

I modified it to use Proxy# instead.

This is a point on which I'm somewhat hazy, but I think Proxy# x -> a requires a function call (albeit to a function whose arguments occupy zero bits), whereas Tagged x a is genuinely represented as a at compile-time? I doubt the difference really matters though.

Though I'm not 100% sure if it's worth it.

It looks like it's just going to require putting corresponding AppendIndices to the context whenever Append is used with polymorphic indices, though this ought to be internal detail.

Yes, I'm on the fence with this one too. The extra constraint will probably be solved automatically in most user code (which will have concrete indices), but it will still potentially show up in error messages and the like. And it does potentially incur some runtime work to get away from an unsafeCoerce that is mostly harmless AFAICS. Or are there more compelling reasons for dropping the unsafeCoerce that I'm missing?

@arybczak
Copy link
Copy Markdown
Collaborator Author

After more consideration let's leave it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants