IRC channel logs


back to list of logs

<zv>oh I see, it's "base"
<zv>that is pretty cool amz3
***carboran1 is now known as superacid-carbor
***superacid-carbor is now known as Carborane-acid
<sapientech>Hi all got a good question for yall. I am trying to make a meta-vtable that derives <applicable-struct-vtable>, not <standard-vtable>
<sapientech>to make it derive from standard-vtable, I do (make-vtable (string-append standard-vtable-fields "some new ones") my-print-proc)
<sapientech>problem is, i have yet to find a way to make a meta-vtable that derives from applicable-struct-vtable
<sapientech>note, that i can make an applicable vtable by doing (make-struct/no-tail 'some-new-fields print-proc)
<sapientech>*(make-struct/no-tail <applicable-struct-vtable> 'some-new-fields print-proc)
<sapientech>but using this vtable in a make-struct procedure creates a struct, but not a vtable, which I want
<sapientech>while the vtable defined above with standard-vtable, is a meta-vtable
<sapientech>any help would be great :)
<sapientech>looks like app-struct-vtable-vtable is defined in struct.c, but there is no mechanism to roll your own
<sapientech>i imagine this is because make-vtable-vtable is deprecated?
<amz3>héllo #guile :)
<ArneBab>wingo: this also happens when I let-bind both values:
<ArneBab>(let ((x '(1 2 3))(y '(1 2 3)))
<ArneBab> (display x)(newline)
<ArneBab> (list-set! y 0 0)
<ArneBab> (display x)(newline))
<ArneBab>it does not happen when I (define x) and (define y)
<ArneBab>(define x '(1 2 3))(define y '(1 2 3))
<ArneBab>(list-set! y 0 0)
<ArneBab>I’m sure there’s a deeper reason due to which it is logical, but is this difference between defined variables and let-bound variables intentional?
<lloda>(list-set! y 0 0) is an error in both cases. The different behavior is down to what the compiler optimizes or not. If the literal gets put into the read only data segment you might even get a segfault. It's just not being checked.
<lloda>so not intentional, no. set!ing a literal is an error, you're getting undefined behavior.
<ArneBab>if I (import (oop goops)), (class-of '(1 2 3)) gives me a pair, just like it does for (class-of (list 1 2 3)) - should it say something different there?
<ArneBab>or is there a better way to find out whether I can set! the (1 2 3)?
<lloda>I know nothing about goops, but I don't think being a literal or not has anything to do with the class of an object
<lloda>Someone correct me, but I don't think there's any way right now. Make copies if you want to be sure
<dsmith-work>Happy Friday, Guilers!!
<ArneBab>lloda: thank you (I hope I’ll find a way)
<lloda>yw, I agree it's a real problem, there shouldn't be undefined behavior or segfaults with pure Scheme code.
<lloda>I think Guile knows internally so the checks shouldn't be hard to add, but you'd need to be familiar with the compiler first.
<dsmith-work>ArneBab: It works if you use (list 1 2 3) instead of '(1 2 3)
<dsmith-work>The compiler is free to make both x and y be the same list.
<dsmith-work>The compiler (currently) does not optimize between top-level expressions., So it does do the constant de-duplication when you use (define)
<dsmith-work>s/does do/does not do/
<dsmith-work>If you use (list) instead of (quote) you get a fresh list each time, so you can mutate one without touching the other
<random-nick>ArneBab: well it is a pair, but the one made by quote is a literal
<random-nick>I think guile stores literals in a special part of the .go file?
<dsmith-work>(let ((x (list 1 2 3)) (y (list 1 2 3))) (eq? x y))
<dsmith-work>$3 = #f
<dsmith-work>(let ((x '(1 2 3)) (y '(1 2 3))) (eq? x y))
<dsmith-work>$4 = #t
<dsmith-work>scheme@(guile-user)> (define a '(1 2 3))
<dsmith-work>scheme@(guile-user)> (define b '(1 2 3))
<dsmith-work>scheme@(guile-user)> (eq? a b)
<dsmith-work>$6 = #f
<dsmith-work>(begin (define a '(1 2 3)) (define b '(1 2 3)) (eq? a b))
<dsmith-work>$7 = #t
<ArneBab>dsmith-work: yes (I tried the list, too)
<ArneBab>dsmith-work: that’s pretty dangerous, though - quite a bit more surprising than the mutable lists in Python.
<ArneBab>dsmith-work: in racket and chicken (let ((x '(1 2 3)) (y '(1 2 3))) (eq? x y)) ⇒ #f
<dsmith-work>As has been said, the real bug is that list-set! really ought to be throwing an error when applied to a literal/constant list.
<ArneBab>but how do we write any function which mutates anything?
<ArneBab>How do I ensure that some variable I get isn’t literal and mutating something else somewhere else?
<dsmith-work>(list 1 2 3) returns a fresh list each time, and it mutable. '(1 2 3) can possibly return the exact same list each time, and should be immutable.
<ArneBab>but when I get a mutable list, I don’t want to copy it, when I get a literal, I do need to copy it
<dsmith-work>I don't know.
<ArneBab>I could do (cons (car l) (cdr l))
<ArneBab>but that might not work…
<ArneBab>and might be optimized away
<dsmith-work>(apply list the-thing) perhaps?
<dsmith-work>ArneBab: My scheme is weak and out-of-practice
<ArneBab>if I apply list to a list that seems more expensive than to a literal
<ArneBab>,t (let ((a (list 1 2 3))) (let lp ((n 1000000)(b a)) (if (= n 0) #t (begin (lp (- n 1) (apply list a))))))
<ArneBab>⇒ 0.3
<ArneBab>,t (let ((a '(1 2 3))) (let lp ((n 1000000)(b a)) (if (= n 0) #t (begin (lp (- n 1) (apply list a))))))
<ArneBab>⇒ 0.03
<ArneBab>argl, disassemble shows that with '(1 2 3) the whole loop is optimized away…
<ArneBab>(define (f a) (let lp ((n 1000000)(b a)) (if (= n 0) #t (begin (lp (- n 1) (apply list a))))))
<ArneBab>,t (let ((a '(1 2 3))) (f a)) ⇒ 0.26 seconds
<ArneBab>,t (let ((a (list 1 2 3))) (f a)) ⇒ 0.26 seconds
<dsmith-work>ArneBab: Heh.
<ArneBab>I currently cannot subtract the cost of the pure loop because when I try that it gets optimized away :)
<dsmith-work>ArneBab: Trying to find the cost of copying the list?
<dsmith-work>Hm. Well, if some funtion mutates it's args, it should be documeted that you can't pass in constant lists.
<ArneBab>that means that every function which uses a function which uses a function which mutates its arguments must document that
<dsmith-work>Yeah. Usually with a !
<dsmith-work>Most things don't mutate
<ArneBab>so to get rid of mutation, I need to transform to a list? — do we have a copy constructor which does that for all types which might be mutated?
<ArneBab>(I had thought let would do it, but it doesn’t)
<dsmith-work>The let created a new binding, but not a copy of the whole list
<ArneBab>something to pull literal constants in a variable into an internal structure which I can mutate without affecting other instances of the data
<ArneBab>the compiler can obviously distinguish them
<ArneBab>so there must be a way…
<dsmith-work>ArneBab: wingo would know
<dsmith-work>,optimize (let ((x '(1 2 3))(y '(1 2 3))) (display x)(newline) (list-set! y 0 0) (display x)(newline))
<dsmith-work>$1 = (begin
<dsmith-work> (display '(1 2 3))
<dsmith-work> (newline)
<dsmith-work> (list-set! '(1 2 3) 0 0)
<dsmith-work> (display '(1 2 3))
<dsmith-work> (newline))
<dsmith-work>,optimize (let ((x (list 1 2 3))(y (list 1 2 3))) (display x)(newline) (list-set! y 0 0) (display x)(newline))
<dsmith-work>$2 = (let ((x (list 1 2 3)) (y (list 1 2 3)))
<dsmith-work> (display x)
<dsmith-work> (newline)
<dsmith-work> (list-set! y 0 0)
<dsmith-work> (display x)
<dsmith-work> (newline))
<dsmith-work>ArneBab: The compiler knows!
<ArneBab>dsmith-work: oh, wow!
<ArneBab>now it just needs to issue a warning when it encounters a *! function operating on literal datatypes
<ArneBab>"warning, this is really dangerous and can break your program in strange and wonderful ways. Please do not pass literal values to mutating functions."
<dsmith-work>... at your peril.
<davexunit>it's really an error.
<davexunit>not a warning.
<ArneBab>but it might already have been used in existing code, so signaling an error could break existing code.
<ArneBab>I know I used it - that’s how I stumbled over it.
<davexunit>that code is wrong.
<davexunit>and should break.
<ArneBab>not due to updating Guile
<amz3>then it's a feature \\o/
<ArneBab>this is stuff which worked without problems in 1.8, it sometimes had wrong results in 2.x, but it still worked for most occassions, so it should throw a dire warning.
<ArneBab>part of the program might have created wrong results, but erroring out would break all the non-problematic parts of the program, too.
<davexunit>okay whatever.
<ArneBab>imagine Guile 2.2 not being shipped in distros because some only barely maintained program using mutation on literals stops working - even though the behavior was wrong before.
<davexunit>I won't consider that situation until there is software that is actually breaking because of it.
<davexunit>it's better to be correct.
<davexunit>but I'm not a maintainer so this is all meaningless.
<dsmith-work>Is it right to maintain bug compatabilty at all costs?
<dsmith-work>If old code relied on incorrect code not throwing an error, does that mean that error should never get fixed?
<dsmith-work>Old C code used to do mktemp("const_str_XXXXXX"). That's an error now.
<daviid>ArneBab: I'm not a mainainer either, but I agree with davexunit here, fwiw. and distro must 'force' these packages/code that mutate literal to be changed, or otherwize removed from the distro, not guile...
<ArneBab>dsmith-work: I don’t want another lilypond
<ArneBab>dsmith-work: I don’t want another lilypond situation
<OrangeShark>using '(1 2 3) does seem like an easy mistake to do...
<ArneBab>(i do want another killer application like lilypond, but I don’t want another situation where this killer application breaks due to a Guile update so the new Guile version does not get shipped by default for half a decade)
<ArneBab>(and I don’t want to assign any blame in any direction)
<OrangeShark>maybe more testing on applications using guile should be done?
<daviid>what 'killer application' could that be, that mutates literals ? :) no way
<ArneBab>if the compiler throws a warning, that can be done much more easily
<ArneBab>daviid: did you check whether GNU Cash or lilypond do?
<ArneBab>especially given that in GNU Cash users can write their own reporting scripts which then get run.
<daviid>ArneBab: this discussion is useless anyway, guile-2.2 is already designed and 99% done already ...
<dsmith-work>daviid: "kiiler" app? "mutates"?
<dsmith-work>Like jack-the-ripper or something?
<ArneBab>daviid: and Guile 2.2 is really cool!
<OrangeShark>does 2.2 throw an error for mutating quoted lists?
<dsmith-work>Not mine
<dsmith-work>(list-set! '(1 2 3) 0 0)
<dsmith-work>$1 = 0
<dsmith-work>$2 = "2.1.4"
<daviid>dsmith-work: I was 'reusing' ArneBab's terms> ... a killer app ... never mind :)
<dsmith-work>daviid: Yes!
<daviid>useless conversation anyway, I'm out of it now, I have to concentrate on something else ...
<OrangeShark>is anyone planning on adding errors for that? Doesn't seem like it
<dsmith-work>"Note that an application must not attempt to modify literal lists or vectors obtained from a quote form, since they may be in read-only memory."
<dsmith-work>OrangeShark: I seem to remember it being mentioned, but not where or by who
<dsmith-work>Probably by wingo
<dsmith-work><wingo> (list-set! '(1 2 3) 0 0) should error
<OrangeShark>same thing happens for literal strings as well, right?
<OrangeShark>or maybe only (quote "abc")
<OrangeShark>oh, strings has this copy on write feature, so maybe not an issue
<dsmith-work>A compiler could combine all references to the same string literal to only one storage location.
<dsmith-work>C compilers/linkers can do that
<OrangeShark>yes, I know some compilers do that. Was wondering if Guile did the same thing
<OrangeShark>I should poke at guile's source code more to leaern
<dsmith-work>Not sure