beneroth changed the topic of #picolisp to: PicoLisp language | The scalpel of software development | Channel Log: https://libera.irclog.whitequark.org/picolisp | Check www.picolisp.com for more information
pablo_escoberg has quit [Ping timeout: 246 seconds]
pablo_escoberg has joined #picolisp
<abu[7]> I did not expect that 'dep' makes sense in non-debug (production) code
<abu[7]> Easier than looking at the source properties of a symbol is simply (vi 'dep)
pablo_escoberg has quit [Ping timeout: 246 seconds]
<tankf33der> morning
<abu[7]> Cheers tankf33der!
<tankf33der> i cut huge list idx of indixes to separate file and no crash
<tankf33der> crash when idx touches inner idx
<abu[7]> It is the line: (for r (idx ratr)
<abu[7]> Did you see my mail to Jason?
<abu[7]> What is the value of 'ratr'?
<tankf33der> i tried read all these long emails
<abu[7]> Is this call correct?
<tankf33der> i belive so
<abu[7]> or does it need to be (for r (idx 'ratr) ?
<abu[7]> It is only correct if 'ratr' has a var as the value which holds the tree
<tankf33der> ("192.168.42.1/32" ((dev . "ppp0") NIL (dst . "192.168.42.1/32") NIL (gw . "0.0.0.0") ((flg . "UP,HO")) (nref . "0") ((metric . "50") ((mask . "255.255.255.255") ((irtt . "0"))) (mtu . "0") ((mss . "0"))) (use . "0")))
<tankf33der> this is ratr on call
<tankf33der> crashes in idx 'ratr and idx ratr
<abu[7]> I think it must be (for r (idx 'ratr)
<abu[7]> ("192.168.42.1/32" ... is not an idx variable
<abu[7]> This whole program is a mess, I cannot stand it
aw- has joined #picolisp
<abu[7]> ("192.168.42.1/32" ... is not an idx variable but the idx tree itself
<abu[7]> So I'm sure it must be (for r (idx 'ratr)
<abu[7]> Maybe there are other things wrong too
<tankf33der> crashes
<abu[7]> Crashes inside the 'idx' call?
<tankf33der> another idx calls
<tankf33der> ^^^^
<tankf33der> crashes at first touch i would say
<tankf33der> for never loops
<abu[7]> yes, cause it crashes in 'idx' itself
<abu[7]> In Jason's core dump we see it crashes in llvm~consTree
<abu[7]> So the idx tree must be corrupt
<abu[7]> (idx ratr) or (idx 'ratr) never work? Even at the first call?
<tankf33der> yea
<abu[7]> Can you try to find out where it gets corrupted?
<tankf33der> :)
<tankf33der> impossible
<tankf33der> i found the situation when no crash this night
<tankf33der> remove trailing spaces from input file
<tankf33der> but checked he parses it correctly
<abu[7]> hmm, the behavior is non-predictable
<tankf33der> i wrote a function to traversal idx of idx
<tankf33der> i corrupted immediately after creation
<tankf33der> it corrupted immediately after creation
<abu[7]> How is it created?
<tankf33der> problem in (load-routes)
<tankf33der> this is a long messy story
<tankf33der> i can not describe
<abu[7]> oh :(
aw- has quit [Ping timeout: 246 seconds]
cpli has quit [Ping timeout: 260 seconds]
payphone has quit [Ping timeout: 260 seconds]
casaca has quit [Ping timeout: 260 seconds]
cpli has joined #picolisp
payphone has joined #picolisp
<tankf33der> repeated issue under memory sanitizer
<abu[7]> address 0x00000000000b
<abu[7]> doesn't help
<abu[7]> We need to know where the tree is destroyed
<tankf33der> and how
<tankf33der> afk.
casaca has joined #picolisp
aw- has joined #picolisp
tankf33der has quit [Quit: the lounge - https://webirc.envs.net]
tankf33der has joined #picolisp
beneroth has joined #picolisp
<tankf33der> i see that corruption happens in (for o (json-decode (fd) T) ...
<tankf33der> this is aw's json library
<abu[7]> Good, one step further!
<abu[7]> Does 'json-decode' manipulate an idx ?
<tankf33der> no
<abu[7]> How can it corrupt the tree?
<tankf33der> global *Routes* does not touched
<tankf33der> if i touch global idx inside json it does not crash
<tankf33der> if i *touch* it before for it crashes
<tankf33der> if i *touch* it inside (for o (json-decode (fd) T) call it crashes
<tankf33der> it corrupts in first loop
<abu[7]> With touch you mean (idx 'Tree) ?
<tankf33der> http://ix.io/4CdH
<tankf33der> emulating touch idx of idxz
<tankf33der> emulating touch idx of idx
<tankf33der> what if bug in (for) itself? :)
<abu[7]> I don't think so
<abu[7]> (idx 'Tree) does a non-recursive traversal
<abu[7]> if the tree is not 100% correct, it destroys it even more
<abu[7]> It traverses by changing pointers up and down while going through the tree
<abu[7]> So the tree is probably corrupt before that
<tankf33der> ok
<tankf33der> so i call (mike) everywhere on the path
<tankf33der> i see the place where this is ok
<abu[7]> good
<tankf33der> i see the places where this is ok
<tankf33der> ok
<abu[7]> But anyway (for r (idx ratr)) is not correct ;)
<abu[7]> needs a quote
<abu[7]> not sure what happens
<tankf33der> right, ok
<abu[7]> I think (idx ratr) does nothing and returns NIL
<tankf33der> what if he manipulates the tree himself
<abu[7]> who, Jason?
<tankf33der> yes
<abu[7]> No idea ;)
<abu[7]> The value of 'r' is ("192.168.42.1/32" ((dev . "ppp0")
<abu[7]> ...
<abu[7]> right?
<abu[7]> (idx r) returns NIL then
<abu[7]> cause the VAL of the 'var' argument is "192.168.42.1/32" which is atomic
<tankf33der> right
<tankf33der> fixed (for r (idx 'ratr)) and now problem moved forward
<tankf33der> i see crash starts at another place
<abu[7]> ok
<tankf33der> crash disappeared
<abu[7]> oh
<tankf33der> do not see crash :) searching from scratch
<tankf33der> i see that no more crash after (for r (idx 'ratr) fix
<abu[7]> Strange, because it is a no-op
<abu[7]> or, perhaps there is different input sometimes so that it chokes
<abu[7]> Do you know if the 'cnt' function is called somewhere in aw-'s json lib?
<abu[7]> Because Jason does (let (cnt 0 ...
<abu[7]> I told him, but he did not fix yet
<abu[7]> All variables are lowercase anyway, so not good
<tankf33der> Do you know if the 'cnt' function is called somewhere in aw-'s json lib?
<tankf33der> no
<abu[7]> ok
<abu[7]> Anyway this would crash *immediately*
<abu[7]> A also wrote to Jason about (idx ratr) this morning, but no reaction
<tankf33der> i sent email with patch recently
<abu[7]> good
<beneroth> you are so nice and helpful people
<beneroth> probably we should stress the naming conventions more to beginners and maybe in the documentation/website/etc. So many people who don't follow it and get into the weirdest issues.
<beneroth> the naming convention is not mandatory and not enforced, but without fully grokking pil it's just so easy to shot yourself when not following it.
<abu[7]> Very true!
<abu[7]> I should extend 'lint' to check this
<aw-> tankf33der: i do not use 'cnt'
<aw-> is there a bug in my lib?
<aw-> sorry i didnt see the full discussion
<tankf33der> aw-: no bugz, all ok
<aw-> (let (cnt 0 ...
<aw-> that's not good
<abu[7]> Indeed :)
pablo_escoberg has joined #picolisp
<pablo_escoberg> There's something to be said for a path like: lint gives warnings about naming convention violations, then the reader gives warnings about it, then it enforces it.  Eventually, you'd be breaking older code, but it may be worth it (I actually have no idea whether the last step would be worth it).
<abu[7]> lint can give diagnostics, but I think the reader cannot. It is all legal data.
<pablo_escoberg> in that case, we should just seriously encourage the use of `lint`.  I almost forgot it existed, and it's really very useful.
<pablo_escoberg> For newbies, of course.  You more experienced folks may not find it as handy.
<aw-> never use dit
<aw-> hahahaa
seninha has joined #picolisp
<pablo_escoberg> LOL.  really handy for newbies, though, and the docs should probably reflect that.
<beneroth> pablo_escoberg, enforce is no good, violates the "programmer is in full control"-principle. I have code where I purposely customize built-ins in a (let).
<abu[7]> In fact, I also very often forget about it. Now I have (lintAll) as the first history entry in my .pilrc file
<abu[7]> The second entry is (shadows T)
<abu[7]> and the third one is (namespaces T)
<beneroth> in the end, you can never entirely prevent a bad programmer from fucking up. Some languages (e.g. C#, Java) are full of constraints on the programmer and handrails, which kinda results in a minimum productivity even with bad programmers, but they also often restricts good programmers from being efficient (by disallowing certain stuff, and by the increased verbosity requiring way more typing)
<abu[7]> Right
<beneroth> picolisp is on the other end of the spectrum. If you follow the naming conventions and you are over beginner mistakes (e.g. calling a symbol which has no function definition) you hardly make grave mistakes. But if you want to do weird shit it lets you.
<beneroth> just now I'm programming a C# once again, and again I'm pissed at it not letting me edit a list while looping over it (with foreach).
<abu[7]> You must use a specific editor?
<beneroth> yeah that's something that can give very funny bugs. But having to maintain additional lists to hold your planned changes and then applying it in a second round is kinda bloaty
<beneroth> abu[7], no, the compiler doesn't allow you to modify a list within the for-loop body
<abu[7]> Ah
<beneroth> use case is going through a list, checking the elements, removing the elements from the same list. here in C# I have to first iterate over the list and put all elements which I want to remove into a second list, and then go through that second list again to do the removal from the first list.
<abu[7]> I see, destructive operations are artificially limited
<beneroth> yes. but only in some cases. it's the usual "security/safety through blacklists" which doesn't work because you hardly can enumerate all bad stuff. the correct why would be whitelisting instead.
<beneroth> s/correct why/correct way
<beneroth> [OT] btw. using Microsoft Cloud for anything and claiming to care about security is now definitely completely BS. A few weeks ago it became known that some guys managed to make a clon of MS master key for all MS authentication services (so not only affecting MS Services but also third-party services/websites which allow Microsoft Login). And now this week one customer found that their Cloud tenant isolation is also insecure, allowing reading secrets
<beneroth> from other customers on the same hardware server.
<abu[7]> Oha
<abu[7]> I don't use any third party cloud
<aw-> beneroth: why would you want to do that? ;) ;)
<aw-> (re: modify a list within the for-loop)
<aw-> i'm kidding btw
<abu[7]> like this
<abu[7]> : (setq L (range 1 7))
<abu[7]> -> (1 2 3 4 5 6 7)
<abu[7]> : (for N L (put L 6 'a) (printsp N))
<abu[7]> : L
<abu[7]> 1 2 3 4 5 a 7 -> 7
<abu[7]> -> (1 2 3 4 5 a 7)
<abu[7]> Never tried, one must be sure what one wants to do
<pablo_escoberg> beneroth good points.  Lint is still great for newbies and I will be using it a lot more from hereon. Would have saved me from some pretty painful stuff if I'd had it more top of mind.
<beneroth> aw-, yeah ;-)
<beneroth> pablo_escoberg, T
aw- has quit [Ping timeout: 260 seconds]
<pablo_escoberg> Is there a way to call `foo~bar` if I don't know foo and/or bar in advance?  I know `get` is wrong, but is there another way or am I barking up the wrong tree here?
<abu[7]> You mean a computed call?
<abu[7]> 'get' is good
<abu[7]> ((get Obj 'foo) arg1 arg2)
<abu[7]> ah
<abu[7]> you mean the namespace
<abu[7]> foo is not an attribute of bar
<abu[7]> bar may be in several namespaces or in none
<pablo_escoberg> right, but in my particular case, I know foo, and I know bar is in foo, but I don't know foo (could be one of several things, and if it's not in bar it's an error).
<abu[7]> So you must already have foo obtained from somewhere. The namespace is irrelevant, just I/O
<abu[7]> ok
<abu[7]> Then ((intern "bar" 'foo) arg)
aw- has joined #picolisp
<abu[7]> : ((intern "+" 'pico) 3 4)
<abu[7]> -> 7
<pablo_escoberg> ah, great.  That will do the trick.
pablo_escoberg has quit [Quit: Client closed]
pablo_escoberg has joined #picolisp
<abu[7]> hmm, not completely what you wanted
<abu[7]> 'intern' gives no error
<abu[7]> If not in bar, it will be interner there
<abu[7]> *interned
<abu[7]> Same as reading foo~bar
<pablo_escoberg> Oh, actually, doesn't exactly do what I need.  Seems to return an external symbol with the same name as the symbol I want.
<abu[7]> an external symbol? Can't be ...
<pablo_escoberg> I'm actually doing this for a class, so it's `(intern '+User 'entities) -> "+User"` when I actually want just `+User`
<pablo_escoberg> namespaces may not be ideal for dynamic dispatch, but I can't seem to find a better mechanism that doesn't require explicit declaration.
<abu[7]> First of all, do (intern "+User" 'entities)
<pablo_escoberg> same result...
<abu[7]> otherwise +User is first (also) interned in the current namespace (by the reader)
<abu[7]> No, it is correct
<abu[7]> of course the symbol *prints* as "+User" if it is in another namespace
<abu[7]> which is not in the current search order
<pablo_escoberg> but I can actually send it messages?
<abu[7]> This depends on the symbol
<abu[7]> not the namespace
<pablo_escoberg> so I can do (send 'get (intern "+User" 'entities))
<abu[7]> if it is an object inheritating methods
<abu[7]> yes
<abu[7]> Note that 'get>' is recommended
<abu[7]> 'send' is not neede
abu[7] has left #picolisp [#picolisp]
abu[7] has joined #picolisp
<abu[7]> oops
<pablo_escoberg> right, and that's what I'm actually using.  It's one of the naming conventions I'm least used to.
<abu[7]> I meant (get> (intern ...
<abu[7]> ok
<beneroth> pablo_escoberg, "external symbol" is a specific term in picolisp. an external symbol is a symbol which rests in picolisp database.
<beneroth> I suspect you meant something else
<pablo_escoberg> SHIT!  Transitory symbol!
<abu[7]> yes, transient :)
<pablo_escoberg> dammit!  I will get the terminology right one of these days...
<abu[7]> I'm sure
<beneroth> the word transient in "transient symbol" refers to the scope, as a transient is scoped per file (like the file being its own namespace, but there is no symbol in pico or any other namespace making that namespace accessible)
<pablo_escoberg> ok, that makes sense.
<beneroth> :)
<abu[7]> What I wanted to explain before, if you do (intern "+User" 'entities) you get back another symbol "+User" than the one in the call
<abu[7]> They happen to have the same name
<abu[7]> (let S "+User" (== S (intern S 'entities)'entities)'entities) should return NIL
<abu[7]> oops
<abu[7]> (let S "+User" (== S (intern S 'entities))) should return NIL
<abu[7]> The one returned is the class with all its definitions, S is just a plain transient sym
<pablo_escoberg> yes, I understood that.  It's confusing that way because I'm seeing a transient symbol but getting an internal symbol.
<beneroth> don't use namespaces then it's less confusing :)
<pablo_escoberg> LOL.  I would love to avoid them, but there really doesn't appear to be another way to do dynamic dispatch to class methods if the class is not known in advance.
<abu[7]> You just need to put 'entities' also in the search order somewhere, then it prints either as '+user' or as 'entities~+User'
<pablo_escoberg> oh, ok, I think I can manage that.  But as long as it works, it's not really necessary.
<beneroth> I suspect you are doing it way too complicated
<beneroth> even if you do some kind of "chain of responsibility" pattern, you will have a list of potential classes, no?
<beneroth> possible candidates to which you want to dispatch, no?
pablo_escoberg has quit [Quit: Client closed]
pablo_escoberg has joined #picolisp
<pablo_escoberg> no,  the list of classes to dispatch to is set by the application.  And the whole point is to avoid having to type things twice.  I already do with `local` but I can live with that.  I really don't want to have to do it a third time.
<pablo_escoberg> So I think of the `local` thing as kind of like declaring my classes, then defining them.
<pablo_escoberg> but I should be able to register them automatically with a single statement (`symbols` in this case) which encapsulates all the classes.
<abu[7]> If I understand correctly, then PilBox is such a thing
<abu[7]> There are multiple DBs each with its own model running in the same process
<abu[7]> (symbols ...) separates them
<pablo_escoberg> great, I'll see if I can find the code.  For now, struggling with a weird bug that doesn't happen in debug mode (Heisenbug I think you call it; love that!).  Once I straighten that out I'll look at the PilBox code and see if I can find what I need there.
<abu[7]> Oh, another Heisenbug today! ;)
<pablo_escoberg> FWIW, (setq Cls (or (intern (to_cls_nm noun) ns) (intern (to_cls_nm (singularize noun) ns )))) .  Maybe you can spot it quickly.  Getting "to_cls_nme -- Undefined` .  Works fine if I comment out the line and put in a break point.
<pablo_escoberg> the weird thing is, I have to comment out the line.  I would think the breakpoint stops the thing before it gets to that line...
<abu[7]> Why the 'or'? I think 'intern' never returns NIL (?)
<pablo_escoberg> oh, great.  I have to figure out a different way to test for that.
<abu[7]> That's what I meant a few hours ago
<abu[7]> 'intern' will not give an "error"
<abu[7]> It always succeeds, just like 'read'
<pablo_escoberg> oh, ok.  I just need to surround it with (isa '+Rest) and that will do it.
<pablo_escoberg> and hey, maybe it will fix the bug as well :)
<abu[7]> Yes, checking the returned symbol
<pablo_escoberg> OK, changed the code to `(setq Cls (or (isa '+Rest (intern (to_cls_nm noun) ns)) (intern (to_cls_nm (singularize noun) ns ))))`.  Still same weird behavior.  As long as the line is commented out, it runs fine in the REPL, but gives an error even when there is a breakpoint in front of it.
<abu[7]> If the error is before the break, then the problem must be earlier
<abu[7]> A heisenbug disappears if the memory layout is slightly different
<abu[7]> Then (gc) runs at different times in different places
<pablo_escoberg> Oh, I get it.  I had the breakpoint in the function body like this: (!).
<abu[7]> this is good
<pablo_escoberg> I guess that doesn't do what I expect.
<abu[7]> But the above line is perhaps not guilty
<pablo_escoberg> well, it appears to run the line after in any event.
<abu[7]> it just changes the env
<pablo_escoberg> As long as I comment it out, it's fine.
<abu[7]> Try (traceAll) to see where it crashess
<pablo_escoberg> And now that I put the exclamation point in the list itself, the bug happens in the REPL too.  So something about the placement of the !
<abu[7]> (if at all)
<abu[7]> The ! must be consed into an expression
<abu[7]> (! car Lst)
<abu[7]> (de f () (a b) (c d))
<abu[7]> (debug 'f)
<abu[7]> (pp 'f) gives (! a b) (! c d)
<pablo_escoberg> right.  So what happens if I do (car Lst) (!) (car Lst2)
<pablo_escoberg> whatever that does, probably has to do with namespaces
<abu[7]> This may break things if just one exe is expected
<abu[7]> (if (foo) (a) (b))
<abu[7]> (if (foo) (!) (a) (b)) is different
<pablo_escoberg> it's in a `(de fun ...)`
<abu[7]> (a) goes into the else part
<pablo_escoberg> right.
<pablo_escoberg> back in a few...
<abu[7]> So best is (if (foo) (! a) (b))
<abu[7]> it stops before evaluating (a)
<pablo_escoberg> This is actually pretty wild.  Here's the current state of the file:
<pablo_escoberg> (de process_req ()
<pablo_escoberg>   (setq noun (car (pth)) ns (config ns))
<pablo_escoberg>   (!)
<pablo_escoberg>   #(! setq Cls (or (isa '+Rest (intern (to_cls_nm noun) ns)) (intern (to_cls_nm (singularize noun) ns ))))
<pablo_escoberg> )
<pablo_escoberg> If I run it in debug and paste that line in, it works as expected.  Uncomment that line, and it fails even in debug mode in the REPL.  Truly bizarre.
<abu[7]> Note that 'ns' is a function
<abu[7]> Better use *Ns
<abu[7]> for a global
<pablo_escoberg> indeed.  Thanks.
<abu[7]> You should try to find which function exactly crashes
<abu[7]> Start with (traceAll)
<abu[7]> hoping that the crash still happens
<abu[7]> With traceAll you find the Lisp function
<pablo_escoberg> OK, not exactly sure why this works, but  (setq Cls (or (isa '+Rest (intern (util~to_cls_nm noun) ns)) (intern (util~to_cls_nm (singularize noun) ns ))))
<abu[7]> Then you can manually step through it
<abu[7]> or insert (msg ...) calls
<pablo_escoberg> well, it
<pablo_escoberg> 's fixed, but none of that would likely have worked since I couldn't reproduce it in debug mode.
<abu[7]> I would always work in debug mode during development
<abu[7]> but even so of course the crash may disappear
<pablo_escoberg> it's more namespace weirdness (yes, I know, beneroth :D) and I don't understand why it needs to be there, but for now I'll leave it.
<pablo_escoberg> yeah, I always work in debug mode unless I forget the `+` :D
<abu[7]> I suspect the problem is not gone, just invisible
<pablo_escoberg> probably true.  But next time it comes up hopefully I'll have more info to fix it.
<abu[7]> good
<abu[7]> ops, I was wrong with 'ns'
<abu[7]> it is 'nsp' :)
<abu[7]> Still, better stay with naming conventions
<pablo_escoberg> yeah, absolutely.
<beneroth> ¯\_(ツ)_/¯
<beneroth> told ya ;-) but hey, maybe you figure it out this way. And if you run into a dead end, you can still go back and try my advice :P
<pablo_escoberg> beneroth I would totally take your advice if I understood it. But it seems to me like what you suggested would require listing the classes again.  I would even be ok with that if `local` accepted a variable rather than a literal list but this way I actually need to go to 3 different places when I want to declare a new class.  2 Places bugs me a
<pablo_escoberg> bit but I can live with it.  3 is just a mess waiting to happen.
<beneroth> I don't see why you would need more than one place
<beneroth> scenario: adding a new class '+Foo with method 'bar> - what you do to add them to your system?
pablo_escoberg has quit [Quit: Client closed]
pablo_escoberg has joined #picolisp
<pablo_escoberg> In my system, they are automatically added to the namespace, where I can find them later.  The only alternative I've come up with is to manually list them at the end of the file, which is truly ugly.  I'm not sure exactly what you're recommending.
<pablo_escoberg> if they were simple functions, I would just define them inside a list and be done with it.
<pablo_escoberg> but these are classes, and well, they don't work that way.
<pablo_escoberg> to be clear, I would do something like ( ('fun1 . '((X) ... )) (fun2 . '((X) ... ))) and then grab the correct one with `assoc`
<beneroth> for what do you need the classes? to group functions? or to hold data?
<beneroth> bbl
<pablo_escoberg> most of them will be database classes (external symbols?) but any class that can respond to one or more of the rest verbs can live in this namespace (or hash or whatever) and be dispatched to.
<beneroth> I recommend to you make multiple smaller prototypes, each one only implementing one aspect of what you want to build, to test your concepts and get an idea about the programming and multiple possible ways to implement it.
<beneroth> then after you deepened your understanding of picolisp system (or whatever you use, you could also try multiple technologies in multiple prototypes to discover the trade-offs) you can build a really good system.
<beneroth> but without a proper understanding you will probably create a monster that might work but not very good and not be maintainable.
<beneroth> in pilDB the classes are inheriting from +Entity, but not themselves external symbols. the records are external symbols.
<beneroth> I recommend you to work through this: https://picolisp-explored.com/introduction-to-the-picolisp-database
pablo_escoberg has quit [Ping timeout: 246 seconds]
pablo_escoberg has joined #picolisp
<pablo_escoberg> Already walked through part of it.  Mostly deals with the GUI, which I won't be using (building an API framework).  And I'm doing exactly what you say.  Building from the ground up.  I've tried several things to group the classes I need in a form I can use.  This is the furthest I've gotten.  There's a sampling bias here (e.g. I won't bother
<pablo_escoberg> you with stuff I already know doesn't work).  I'm ready to try other ways, but I can't think of any to try.  Plus, I think I'm pretty close here.  Still some namespace weirdness to wrangle, but that's the price of a powerful tool.