basilisp
basilisp copied to clipboard
issue when `defrecord` field names have the same names as internal method names
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
- Open up a REPL and define a record with a
seq
field
basilisp.user=> (defrecord Person [seq b c])
<class 'basilisp.user.Person'>
- 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
I think we should throw an error when building a defrecord
with invalid field names.