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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions