Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

issue when defrecord field names have the same names as internal method names #758

Open
ikappaki opened this issue Dec 29, 2023 · 1 comment
Labels
component:basilisp.core Issue pertaining to basilisp.core namespace issue-type:bug Something isn't working

Comments

@ikappaki
Copy link
Contributor

Hi,

there appears to be an issue with defrecord when any of the field names have the same name as any of the deftype methods it implements, e.g. the :seq field in the below comes back as an bounded method

#basilisp.pprint.Person{:c 2 :seq <bound method Person.seq of Person(b=1, c=2, meta=3, _recmap={})> :b 1}

To reproduce

  1. Open up a REPL and define a record with a seq field
basilisp.user=> (defrecord Person [seq b c])
<class 'basilisp.user.Person'>
  1. Create an instance of the record, notice how the seq field is bound to a fn rather than the passed in value of 1, and the rest of the values are shifted
basilisp.user=> (Person. 1 2 3)
#basilisp.user.Person{:c 2 :b 1 :seq <bound method Person.seq of Person(b=1, c=2, meta=3, _recmap={})>}

This is arises due to the definition of Person as a type with a seq method, amongst other methods which result to the same issue, as evident in the below macroexpansion.

Any ideas how easy would be to fix this, if at all possible?

basilisp.user=> (pp/pprint (macroexpand-1 '(defrecord Person [seq b c])))
(do
 (deftype*
  Person
  [seq b c meta _recmap]
  :implements
  [basilisp.lang.interfaces/IPersistentMap
   basilisp.lang.interfaces/IWithMeta
   basilisp.lang.interfaces/IRecord
   python/object]
  (assoc
   [this_13541 & args_5568]
   (basilisp.core/let
    [{map_5570 :map, fields_5569 :fields}
     (basilisp.core/->>
      (basilisp.core/partition 2 args_5568)
      (basilisp.core/group-by
       (basilisp.core/fn
        [[k_5571]]
        (if
         (basilisp.core/contains? #{:seq :c :b} k_5571)
         :fields
         :map))))
     new-recmap_5572
     (basilisp.core/when
      (basilisp.core/seq map_5570)
      ["recmap"
       (basilisp.core/->>
        (basilisp.core/mapcat basilisp.core/identity map_5570)
        (basilisp.core/apply basilisp.core/assoc _recmap))])]
    (basilisp.core/->>
     fields_5569
     (basilisp.core/map
      (basilisp.core/fn
       [[k_5571 v_5573]]
       [(basilisp.core/name k_5571) v_5573]))
     (basilisp.core/mapcat basilisp.core/identity)
     (basilisp.core/concat new-recmap_5572)
     (basilisp.core/apply basilisp.core/evolve this_13541))))
  (cons
   [this_13541 & elems_5574]
   (basilisp.core/loop
    [[f_5575 & r_5576] elems_5574 new-rec_5577 this_13541]
    (basilisp.core/cond
     (basilisp.core/nil? f_5575)
     new-rec_5577
     (basilisp.core/map? f_5575)
     (recur
      r_5576
      (basilisp.core/->>
       (basilisp.core/seq f_5575)
       (basilisp.core/mapcat basilisp.core/identity)
       (basilisp.core/apply basilisp.core/assoc new-rec_5577)))
     (basilisp.core/map-entry? f_5575)
     (recur
      r_5576
      (basilisp.core/assoc
       new-rec_5577
       (basilisp.core/key f_5575)
       (basilisp.core/val f_5575)))
     (basilisp.core/vector? f_5575)
     (recur
      r_5576
      (basilisp.core/apply basilisp.core/assoc new-rec_5577 f_5575))
     (basilisp.core/py-dict? f_5575)
     (recur
      r_5576
      (basilisp.core/->>
       (basilisp.core/seq (basilisp.core/.items f_5575))
       (basilisp.core/map
        (basilisp.core/fn
         [[basilisp.core/k basilisp.core/v]]
         (basilisp.core/map-entry basilisp.core/k basilisp.core/v)))
       (basilisp.core/apply basilisp.core/conj new-rec_5577)))
     :else
     (throw
      (basilisp.core/ex-info
       "Argument to record conj must be another Map or castable to MapEntry"
       {:type (python/type f_5575), :value f_5575})))))
  (empty
   [this_13541]
   (throw (python/TypeError "Cannot create empty Person")))
  (seq
   [this_13541]
   (basilisp.core/concat
    [[:seq seq] [:b b] [:c c]]
    (basilisp.core/seq _recmap)))
  (dissoc
   [this_13541 & ks_5578]
   (basilisp.core/loop
    [[f_5575 & r_5576] ks_5578 new-rec_5577 this_13541]
    (basilisp.core/cond
     (basilisp.core/nil? f_5575)
     new-rec_5577
     (basilisp.core/contains? #{:seq :c :b} f_5575)
     (recur
      r_5576
      (basilisp.core/->>
       (basilisp.core/seq new-rec_5577)
       (basilisp.core/filter
        (basilisp.core/fn
         [[k_5571]]
         (basilisp.core/not= k_5571 f_5575)))
       (basilisp.core/mapcat basilisp.core/identity)
       (basilisp.core/apply basilisp.core/hash-map)))
     (basilisp.core/contains? (.- new-rec_5577 _recmap) f_5575)
     (recur
      r_5576
      (basilisp.core/->>
       (basilisp.core/dissoc (.- new-rec_5577 _recmap) f_5575)
       (basilisp.core/evolve new-rec_5577 "recmap")))
     :else
     (recur r_5576 new-rec_5577))))
  (contains
   [this_13541 k_13544]
   (basilisp.core/or
    (#{:seq :c :b} k_13544)
    (basilisp.core/contains? _recmap k_13544)))
  (entry
   [this_13541 k_13544]
   (basilisp.core/cond
    (basilisp.core/contains? #{:seq :c :b} k_13544)
    (basilisp.core/map-entry
     k_13544
     (python/getattr this_13541 (basilisp.core/munge k_13544)))
    (basilisp.core/contains? _recmap k_13544)
    (basilisp.core/map-entry
     k_13544
     (basilisp.core/get _recmap k_13544))))
  (val-at
   [this_13541 k_13544 & args_5568]
   (basilisp.core/let
    [[default_5579] args_5568]
    (basilisp.core/cond
     (basilisp.core/contains? #{:seq :c :b} k_13544)
     (python/getattr this_13541 (basilisp.core/munge k_13544))
     (basilisp.core/contains? _recmap k_13544)
     (basilisp.core/get _recmap k_13544 default_5579))))
  (__getitem__ [this_13541 k_13544] (. this_13541 entry k_13544))
  (__iter__ [this_13541] (basilisp.core/seq this_13541))
  (__len__
   [this_13541]
   (basilisp.core/+ 3 (basilisp.core/count _recmap)))
  (with-meta
   [this_13541 new-meta_5580]
   (basilisp.core/evolve this_13541 "meta" new-meta_5580))
  (create
   [cls_5581 m_13543]
   (cls_5581
    (basilisp.core/get m_13543 :seq)
    (basilisp.core/get m_13543 :b)
    (basilisp.core/get m_13543 :c)
    nil
    (basilisp.core/dissoc m_13543 :seq :b :c)))
  (_record_lrepr
   [this_13541 py-kwargs_5582]
   (basilisp.core/let
    [{basilisp.core/print-meta :print_meta}
     (basilisp.core/py->lisp py-kwargs_5582)
     basilisp.core/ns-name
     (basilisp.core/name basilisp.core/*ns*)
     basilisp.core/qual-name
     (.- Person __qualname__)]
    (basilisp.core/cond->>
     (basilisp.core/->>
      (basilisp.core/mapcat basilisp.core/identity this_13541)
      (basilisp.core/apply basilisp.core/hash-map)
      (basilisp.core/repr)
      (basilisp.core/str
       "#"
       basilisp.core/ns-name
       "."
       basilisp.core/qual-name))
     basilisp.core/print-meta
     (basilisp.core/str
      "^"
      (basilisp.core/repr (basilisp.core/meta this_13541))
      " "))))
  (__eq__
   [this_13541 other_13542]
   (basilisp.core/or
    (basilisp.core/identical? this_13541 other_13542)
    (basilisp.core/and
     (basilisp.core/instance? (python/type this_13541) other_13542)
     (basilisp.core/=
      [seq b c _recmap]
      [(.- other_13542 seq)
       (.- other_13542 b)
       (.- other_13542 c)
       (.- other_13542 _recmap)]))))
  (__hash__ [this_13541] (basilisp.core/hash [seq b c _recmap])))
 (basilisp.core/defn
  ->Person
  "Create a new instance of the record Person."
  [seq b c]
  (Person seq b c nil {}))
 (basilisp.core/defn
  map->Person
  "Create a new instance of the record Person from a map whose keys correspond to the fields of Person."
  [m_5583]
  ((.- Person create) m_5583))
 Person)
nil
@ikappaki ikappaki changed the title issue when defrecord field names have the same names as internal interface names issue when defrecord field names have the same names as internal method names Dec 29, 2023
@chrisrink10
Copy link
Member

I think we should throw an error when building a defrecord with invalid field names.

@chrisrink10 chrisrink10 added issue-type:bug Something isn't working lang Issue pertaining to Basilisp language modules labels Dec 30, 2023
@chrisrink10 chrisrink10 added component:basilisp.core Issue pertaining to basilisp.core namespace and removed lang Issue pertaining to Basilisp language modules labels Nov 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component:basilisp.core Issue pertaining to basilisp.core namespace issue-type:bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants