libera/#commonlisp - IRC Chatlog
Search
13:26:39
gin
I have been away from this channel for sometime but I haven't stopped learning CL. I think all the effort is finally paying off. I have a small collection of personal tools all written in CL.
17:31:01
alcor
if the data is indeed "just data" then a struct is probably is arguably a better choice than either
17:31:25
_death
it's a pretty general question and I'm inclined to say "it depends".. but then, I think in most cases you should use the most convenient internal representation for your program, and think of the json external data as just something to be translated into this internal representation
17:33:43
alcor
Although I must say, I'm not really a fan of the "anemic data model"-school of design i.e. https://www.martinfowler.com/bliki/AnemicDomainModel.html, especially not in CL. CL has a powerful object model. You can easily have proper domain objects with useful behavior.
17:57:35
beach
A standard class is usually the most convenient choice. The semantics of structs are not so great, and they don't allow multiple inheritance.
17:57:57
beach
mi6x3m: Careful with terminology. Every Common Lisp object is an instance of a class.
18:06:54
mi6x3m
i think i'll just go ahead with a alist / plist thing with semantically processed data
18:17:22
edwlan[m]
e.g. instead of using (cdr (assoc 'foo...)) all over you should typially use a function called FOO that hides that implementation detail
18:22:41
_death
alcor: I don't think this anti-pattern makes a lot of sense when using an object system like CLOS, where behavior belongs in generic functions and not in objects (instances)
18:31:05
alcor
_death: This anti-pattern was popularized by the C++/Java-style sect of OOP. There, it's hard to add behavior to a domain class without accidentially introducting coupling. In the CL/Smalltalk OOP sect, this isn't a problem due to generic functions, advices, and dynamic scoping being available.
18:34:29
mi6x3m
anyone knows of a sane way to get a floating point from a decimal and fraction integers?
18:40:59
gilberth
The sanest probably is taking a detour over ratios. ,(coerce (+ 12 (/ 34 100)) 'single-float)
18:44:17
gilberth
I'd rather do ,(defun foo (m f) (coerce (+ (parse-integer m) (/ (parse-integer f) (expt 10 (length f)))) 'single-float)) ,(foo "10" "34")
18:44:59
alcor
_death: It's in the second camp because it has `become:' allowing one to change an object's identity, in addition full reflection over basically everything in the image
18:47:59
_death
alcor: I don't understand why that makes the anti-pattern inapplicable.. also, I'm not too familiar with smalltalk.. does become: actually affect object identity, or more akin to change-class?
18:48:13
gilberth
The very least you want to do when going with READ-FROM-STRING is (1) bind *REAL-EVAL* to NIL (2) use WITH-STANDARD-IO-SYNTAX, and in your case bind *READ-DEFAULT-FLOAT-FORMAT* as needed. Like (with-standard-io-syntax (let ((*read-eval* nil) (*read-default-float-format* <as you like>)) (read-from-string ...)))
18:52:56
alcor
_death: It does something to the effect of replacing every instance pointer to X in the image with a pointer to instance Y, thus allowing one to transparently implement the decorator pattern i.e. turning an anemic object to a non-anemic one
18:54:44
_death
alcor: I see.. the post by Gilad Bracha says "In the absence of an object table, become: traverses the heap in a manner similar to a garbage collector." ...
18:55:32
semz
mi6x3m: fwiw that op is underspecified, unless you specifically want the fractional part to be hundredths. Is (foo 1 1) 1.1? 1.01? 1.001? etc
18:56:05
fiddlerwoaroof
I think the idea is that the fractional part is divided by 10 raised to its length
18:57:35
gilberth
I believe the ideas was that this FOO gets strings. Perhaps gathered while parsing something.
18:57:49
alcor
_death: Yes, I'm not sure how modern Smalltalk implements it efficiently. It sounds computationally expensive, but powerful (where applicable). Haven't heard of any other platform that can do that.
18:58:28
fiddlerwoaroof
There's probably some sort of inline cache strategy that could handle this relatively efficiently
19:02:04
_death
alcor: what I'm wondering is how useful would that be, if you already have a change-class operator (that doesn't need to change references, in practice using the indirection approach)
19:08:50
alcor
_death: change-class just changes the class, it doesn't touch the state (or rather, it delegates that to update-instance-for-different-class)
19:09:19
alcor
_death: "change-all-references" has at least simpler semantics. It does what it says.
19:09:31
_death
alcor: what you maybe meaning to say is that it may touch the state (via u-i-f-d-c) but not identity
19:11:27
alcor
_death: Kind of. State handling with change-class harbors a few footguns that don't exist with the nuclear approach that is reference patching
19:17:10
alcor
_death: To quote the CLHS: "If in the old class there is any slot of the same name as a local slot in the new-class, the value of that slot is retained"
19:20:00
_death
that just sounds like part of the protocol.. granted if a programmer didn't expect it to happen, may have footache, but doesn't that mean that anything can serve as a footgun?
19:26:03
alcor
It makes naming collisions hurt, but admittedly I don't know how a better solution could look like (perhaps raising a condition?)
19:27:47
alcor
The issue is that it's subtle and causes no explicit error. It's one of these things that can create difficult-to-debug issues.
19:27:58
_death
but I agree that change-class (that requires an instance evolution protocol) is more elaborate