[bof?] ++ nil val in hashmap fails -> feature

Started by hartrock, June 30, 2015, 04:37:16 AM

Previous topic - Next topic

hartrock


sr@mad:~$ newlisp
newLISP v.10.6.2 64-bit on Linux IPv4/6 UTF-8 libffi, options: newlisp -h

> (new Tree 'hm)
hm
> (hm "foo" (+ (or $it 0) 1))
1
> (++ (hm "foo"))
2
> ; OK, but:
> (++ (hm "bar"))

ERR: invalid parameter in function ++
>

Is this a bug, or is there a reason for this behavior?



It would be nice, if checking for nil could be avoided here.

xytroxon

#1
Just use this direct form, no need for (new Tree 'hm), it is created auto-magically ;o)



> (++ iter:baz)
> 1


-- xytroxon
\"Many computers can print only capital letters, so we shall not use lowercase letters.\"

-- Let\'s Talk Lisp (c) 1976

TedWalther

#2
That is a surprising (until you think about it) difference in behavior.



(ctx "bar") returns a setf-able place, or nil.  but referencing an unbound symbol always returns a setf-able place.
Cavemen in bearskins invaded the ivory towers of Artificial Intelligence.  Nine months later, they left with a baby named newLISP.  The women of the ivory towers wept and wailed.  \"Abomination!\" they cried.

hartrock

#3
Thanks for clearifying the difference between symbols and Tree or (ctxt "someKey") hashmap values.



My usecase is a state machine modeled by a hash map with string state IDs as keys, where I want to count state changes. So I have two Tree hash maps: one for the states, another for the counters; both with same string keys.

Best solution I think is to init the corresponding counter hash map val with 0, just with adding a new state to state machine hashmap (which will be done by a func); so above check for nil can be omitted.



Using symbol keys for states like sm:someState would be possible, too; but then there could be a conflict with funcs like sm:add-state, located in same context as state hashmap.

TedWalther

#4
Yes, the way I do it is to override the default functor.



(context 'ctx)
;; override default functor
(define (ctx:ctx a)
  (let (b (sym (string "_" a)))
    (if (args)
      (set b (first (args)))                   ; set the value
      (if (eval b) (eval b) (set b 0))))) ; retrieve the value
(context MAIN)


Now references to an unbound symbol will be automatically set to 0, and setf-able.  With this default functor, now your original code, (++ (hm "foo")) will properly return "1", as you expected.



This seems like it might be a useful design pattern, perhaps suitable for the CodePatterns document if it isn't in there already; I similarly changed the default functor to use a database as a backing store, if a symbol is unbound, it looks it up with SQL and stores it client-side, references thereafter are very speedy.



The way contexts work in newlisp, with this idiom, you still get all the speed advantages of redblack trees that contexts have.  Right Lutz?
Cavemen in bearskins invaded the ivory towers of Artificial Intelligence.  Nine months later, they left with a baby named newLISP.  The women of the ivory towers wept and wailed.  \"Abomination!\" they cried.

xytroxon

#5
You could also use newLISP eval-string.



> (setq id "bar")
> (eval-string (string "(++ hm:" id ")")))
> 1

> (define (++hm id) (eval-string (string "(++ hm:" id ")")))
> (++hm "foo"))
> 1



-- xytroxon
\"Many computers can print only capital letters, so we shall not use lowercase letters.\"

-- Let\'s Talk Lisp (c) 1976