Skip to content

extend-protocol doesn't work on deftype-fn backed types #1024

@borkdude

Description

@borkdude

extend-protocol doesn't work on deftype-fn backed types

Problem

When a deftype is backed by a custom type via :deftype-fn (e.g. SciMap in babashka), extend-protocol on that type doesn't work.

The root cause is that type-impl returns :sci.impl.protocols/reified for ICustomType instances (rather than the specific type symbol like user.MyCache), so the defmethod registered by extend-protocol for the specific type never matches.

Reproduction

(defprotocol Extra (extra [this]))
(extend-protocol Extra
  MyCustomType
  (extra [this] :it-works))
(extra (->MyCustomType ...))
;; => No implementation of method: :extra of protocol: #'user/Extra found for: :sci.impl.protocols/reified

Analysis

In sci.impl.types/type-impl:

  1. SciTypeInstance is checked first → returns specific type symbol (e.g. user.Foo) — extend-protocol works
  2. ICustomType is checked second → returns :sci.impl.protocols/reifiedextend-protocol doesn't match

For the standard SciType path, inline protocol impls are registered as defmethods keyed on the specific type symbol. extend-protocol also registers defmethods for that symbol, so both work.

For custom types (via :deftype-fn), inline protocol impls go through the :reified defmethod which delegates to ICustomType.getMethods(). But extend-protocol registers a defmethod for the specific type symbol, which never fires because type-impl returns :reified.

Possible fix

Make custom type instances also implement SciTypeInstance (or otherwise return a specific type symbol from type-impl), then register a per-type defmethod that delegates to getMethods(). This would let both inline impls and extend-protocol coexist.

This would also open the door to unifying the standard SciType path and the custom type path, since both would use methods-map + per-type defmethod delegation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions