IRC channel logs


back to list of logs

<flatwhatson>civodul: it looks like a doc fix from jpoiret is missing on wip-posix-spawn (posix.texi): "or the more @code{spawn} procedure" -> "or the more primitive @code{spawn} procedure"
<flatwhatson>similarly the docs for `spawn' are improved in that last patch compared to the branch
<dokma>I tried: (module-set! (resolve-module '(system repl common)) '*version* "Something new\n")
<dokma>And it returns the new value from: (module-variable (resolve-module '(system repl common)) '*version*)
<dokma>$9 = #<variable 7fa337ce9c40 value: "Something new\n">
<dokma>module-ref also sees the same value.
<dokma>However, repl-welcome still uses the old greeting when I connect to the repl using: socat - TCP:
<dokma>Which scope sin did I commit here?
<flatwhatson>dokma: it might have been inlined when repl-welcome was compiled
<dokma>hmmm... any easy way to avoid that?
<dokma>prevent compilation?
<flatwhatson>is it visible after ,reload (system repl common)
<dokma>damn... flooding my spacemacs buffer
<flatwhatson>D: oops!
<dokma>I get a ton of Wrong type argument...
<dokma>and it hangs...
<dokma>Doesn't work when I go to a terminal and try the same thing either.
<flatwhatson>nice, same here. that's a nice bug! i guess reloading the repl from inside the repl is a bit like replacing the engine while the car is running
<dokma>Yeah, does sound a bit catch 22ish
<dokma>So basically, no way to alter the greeting of the repl in a clean way?
<flatwhatson>if your aim is to change the welcome banner, setting the following in ~/.guile works: (module-set! (resolve-module '(system repl common)) '*version* "Hello!")
<dokma>I'm using libguile by linking. So the idea is to change the welcome banner of my TCP server that has a guile repl embedded.
<dokma>flatwhatson: but, surprisingly, adding the line to my ~/.guile does nothing for me. Guile 3.0.5.
<dokma>I have already enabled readline and colorized from ~/.guile, so it's not completely useless.
<dokma>flatwhatson: do I need some (use-modules ...) magic to use module-set! inside ~/.guile ??
<a12l>Is there a canonical way to write tests in Guile?
<flatwhatson>dokma: hmm. i'm using guile 3.0.8, and the following in a fresh guile repl works: (begin (module-set! (resolve-module '(system repl common)) '*version* "Hello!\n") (use-modules (system repl server)) (spawn-server))
<flatwhatson>then connecting with "nc localhost 37146", i see the "Hello!" banner
<a12l>Tests that test individual functions
<flatwhatson>a12l: guile provides (srfi srfi-64) which is a standard test library for scheme:
<dokma>flatwhatson: I get absolutely no change in the greeting when using your recipe.
<flatwhatson>interesting! if i test with guile@3.0.7, it doesn't work. on guile@3.0.8, it does!
<dokma>ohhh damn...
<dokma>I don't have anything newer than 3.0.5 from my package manager.
<dokma>look for cross module inlining
<dokma>Something has been done with the very functionality we are poking around.
<flatwhatson>yes, though my expectation would be that inlining would cause this problem, not fix it :P
<dokma>I'm reading it and it sounds backwards.
<flatwhatson>dokma: you could try redefining repl-welcome instead
<a12l>flatwhatson: thanks!
<dokma>flatwhatson: will do that.
<Aurora_v_kosmose>I'm quite glad Guile went the GOOPS way instead of Racket-like message-oriented.
<Aurora_v_kosmose>I was reading Racket docs & figured I'd have a look and while I really like what they did with contracts... I can't say I'm nearly as impressed with the objects.
<Aurora_v_kosmose>Other than the objects, I'm wondering if Guile has considering adding in thread message boxes like both Racket & Gambit have.
<flatwhatson>Aurora_v_kosmose: guile-fibers provides channels, which are what you're asking for IIUC?
<flatwhatson>guile also provides mutexes and condition variables which can be used to write your own thread-safe structures
<Aurora_v_kosmose>Fibers does look interesting.
<haugh>Auroroa_v_kosmose, pardon my ignorance but what does the object system have to do with the async strategy?
<Aurora_v_kosmose>haugh: Nothing much, just two different things I looked at. Or if you mean message-oriented objects, it's a reference to Smalltalk & Objective-C lineage, which Racket references by even keeping method invocation as explicit 'send-ing of messages.
<haugh>Oh that's fascinating, thanks
<flatwhatson>this is commonly referred to as "the actor model"
<Aurora_v_kosmose>Right, that's another name for it.
<Aurora_v_kosmose>To be distinguished from Erlang-style actor model which instead is all about async communication.
<Aurora_v_kosmose>For that there was 8sync some time ago but the lack of news makes me uncertain whether it's simply done or if it was abandoned.
<daviid>a12l: ... tests ... to complete flatwhatson answer, guile-lib provide (unit-test), which i use, which uses goops ...
<flatwhatson>Aurora_v_kosmose: the creator of 8sync went on to write an actor framework called Goblins, and is very busy bootstrapping a non-profit decentralized "social web" platform around it :)
<Aurora_v_kosmose>flatwhatson: Oh that's the same person? I see.
<flatwhatson>Aurora_v_kosmose: #spritely
<daviid>flatwhatson: hello! i did some more tracking, and posted the following question in #gnome-introspection - - maybe you have an idea ... (?)
<flatwhatson>daviid: are you sure that these "return value" functions are the right choice for unpacking the function arguments? those are not return values, after all.
<flatwhatson>it's possible that the unpack routine for pointers works "by accident", because that is simply a pointer underneath it's passed through as-is
<daviid>flatwhatson: i don't understand your suggestion :) i receive a pointer to an ffi-args, i have to 'decode them', to call apply ... what are suggesting?
<daviid>flatwhatson: what i did see, is the trying to extract the ffi-arg value using the guile 'ffi engine' aso fails ... and iiuc your question, the gi_type_info_extract_ffi_return_value calls gi_type_tag_extract_ffi_return_value, and they 'just' extract an ffi value, the name is, imo unfortunate, but i should, by definition, be able to call it on any ffi-arg (pointer), where it is the first or last ffi-arg - if that was not the case, it
<daviid>wopuld mean it would be impossible for any C function,to ge the ffi-value pointed by an ffi-arg (probably badly expressing myself here, not a C expert, but i hope you get the idea of my understanding of the situation ...
<flatwhatson>daviid: see here:
<daviid>though of course, it's been months now, and no experts, not even any of the gi team, ever came with any signle suggestionof 'look into this', this might be the problem ... nothing, you are the only one that looked into this so far :) - all they told me is 'snapshot calls are guarantee to receive proper width and height vlues (what ever that eans
<flatwhatson>that is a callback function written in C which takes its args, and casts them directly to the intended type
<daviid>flatwhatson: that code is chineese for me
<daviid>i do what the guile ffi engine does, that i (moreless understand)
<daviid>and ite returns invariably 0.0
<flatwhatson>where is the guile ffi engine using those gi routines to unpack args?
<daviid>let me point ..
<flatwhatson>this "chinese" is demostrating that args are not wrapped in any values, they're directly pointers to the arguments. see it is casting them in order: double a = *(double*)(*args++); double b = *(double*)(*args++);
<flatwhatson>iiuc these C functions are equivalent to your callback receiving cif, retp, args, user_data
<daviid>in libguile/foreign.c line 997, then 1006 for a double type
<daviid>flatwhatson: you suggest i dereference
<daviid>i can try ofc
<daviid>flatwhatson: could you kindly patch this function for me? - i don't have the experience to do it 'right' in the first place ...
<daviid>flatwhatson: it actually seems (to me, trying to read chineese) they do, line 299, what i try to do copying guile
<daviid>or is there one additional indeirection?
<count3rmeasure>am I fool for thinking that square brackets have to be escaped? like, if I wanted to match [heap], I'm struggling to understand why neither "\[[a-z]\]" or "[[a-z]]" aren't working
<flatwhatson>daviid: your function looks fine to me, simply casting that arg to double. only mistake is that it's not an ffi_arg*, but a void* (untyped pointer)
<flatwhatson>daviid: you probably don't even need a C function for that, just pointer->bytevector and bytevector-ieee-double-ref
<daviid>flatwhatson: would that change if i change it to _ffi_pack_double (void *arg) ?
<flatwhatson>daviid: no practical difference, it's just "wrong" :)
<flatwhatson>or, misleading
<flatwhatson>count3rmeasure: square brackets need to be escaped where? are you talking about regex or something?
<count3rmeasure>my apologies! yeah I'm trying to use ice-9 regexs
<daviid>flatwhatson: but, the question is, i still don't get the answers, do i need to indirect or not, is the double in that location or in a location pointed byu that locat
<count3rmeasure>that was to flatwhatson, apologies
<daviid>i wonder if those value a re just all zero, and they have a bug in GI (unlike they pretend there is no bug ...)
<flatwhatson>count3rmeasure: in regex, yes you need escapes to match a literal "[". in practice this means "\\[" in your pattern to get through guile's string escaping
<daviid>flatwhatson: because at this point, if ytou confirm the snipset is correct, there are no 'intermediare' code, i get the value the callback closure was receiveing, and that is always wrong, for any arg of any virtual function that has a type that is not a pointer ..
<daviid>*the callback closure is receiveing (not was) ...
<daviid>i have asked in C, they don't answer - they just asked how do i know it is a double ...
<daviid>in #c
<count3rmeasure>flatwhatson: thank you
<flatwhatson>daviid: yes maybe it needs double de-referencing, worth trying anyway
<daviid>flatwhatson: ok, how?
<daviid>dble = *(double *) arg; -> ... (?)
<daviid>i'll try immediately ofc
<flatwhatson>make your function take (void **arg), and dble = *(double *)(*arg)
<daviid>ok, let me try
<flatwhatson>notice that's how they're doing it in that libffi unit test: double a = *(double*)(*args++);
<daviid>right, but i was and still am unable to undewrstand that code
<daviid>you don't know chineese by reading chinees :)
<daviid>flatwhatson: that worked
<flatwhatson>dereference args giving a void*, cast it to double*, then dereference that to get the double value. also as a side effect increment the args pointer
<flatwhatson>daviid: horay!!
<flatwhatson>so you are getting correct 32.0 values to your callback now?
<daviid>flatwhatson: here -
<daviid>of course the scheme values a re still incorrect, i didn't change the scheme code yet
<flatwhatson>nice, that seems like mystery solved
<daviid>indeed, now i ned to ge this 'right' for all types, what about the pointers then ..
<daviid>flatwhatson: many thanks!
<flatwhatson>i think you'll need to switch on cif->arg_types[i]->type
<daviid>flatwhatson: but i am in scheme 'for the real callback closure'
<daviid>i need to dereference i guess
<daviid>flatwhatson: what wre you referig to actually cif->arg_types[i]->type, in which of the code we shared while debugging you suggest i do that? still half lost ...
<flatwhatson>the scheme callback gets the cif passed in, maybe a C helper is needed: unsigned short gg_ffi_arg_type(ffi_cif *cif, size_t ix) { return cif->arg_types[ix]->type; }
<flatwhatson>then you can use a case in scheme to choose the proper dereferencing helper based on that type code
<flatwhatson>a more optimal approach would be to use libguile properly, write a C function which given cif and args, unpacks all args and returns multiple scheme values
<daviid>lost again - the arg type are correct, the value were always ncorrect, except for pointer (but now i doubt for those value as well)
<flatwhatson>you are getting raw pointers to the arguments, but to decode them properly you need to know their type
<flatwhatson>that is encoded in the cif. you know that, because you put it there in the first place :)
<flatwhatson>daviid: exactly like the "pack" function you linked from libguile/foreign.c
<daviid>flatwhatson: yes but ... ah, oh :) - no, no libguile :), i want to keep my callback closure in scheme, so i'd rather patch the one i have -
<daviid>there is no reason not to get this solved in this callback closure - (which actually starts line 11 ...)
<daviid>all i need, iiuc, is to feed gi-type-info-extract-ffi-return-value type-info ot with ffi-arg as i do, but a dereference fii-arg
<flatwhatson>daviid: no, those GI functions are not useful to you, you're dealing with stuff straight from libffi
<flatwhatson>you just need two steps for each argument: get its type, then depending on that, get the value
<flatwhatson>the gg_ffi_arg_type function i pasted above gives you the type as a numeric code (like you already see from those printfs)
<flatwhatson>then you can (case type ((3) (ffi-pack-double ffi-arg)) ((14) (ffi-pack-pointer ffi-arg)) ...
<daviid>ok, so you are telling i can _not_ write this in scheme, there is no way to extract an ffi-arg values from scheme?
<daviid>i have all those types, not because there are in the cif, but because there are in GI, and so the <argument> instances know their types, so does <callable> instances ... i have the type, i have the *ffi-arg ... how come i can't process from scheme?
<flatwhatson>daviid: ok, if you know the type, you just need to call the appropriate dereferencing function
<daviid>i filled the cif usig the type-info tags ...
<flatwhatson>makes sense, i lost track with all this redundancy between GI and FFI libs
<flatwhatson>so if you have a double*, you can use pointer->bytevector with bytevector-ieee-double-ref
<daviid>ok, so i need to writ my gi-type-tag-extract-ffi-value
<daviid>flatwhatson: yes, but i ned to cover all types ocf
<daviid>*need to cover all types
<flatwhatson>but you can't just write one function, because each C function returns a single type
<flatwhatson>that's why you need to switch on type in scheme, and call the appropriate decoding function in C
<flatwhatson>one C function for each type you need to unpack
<flatwhatson>OR, use libguile which can return an SCM holding any scheme type :)
<flatwhatson>in fact guile already has this whole function, called invoke_closure, implemented in foreign.c
<flatwhatson>(though same problem, it's not a public interface)
<daviid>ah - i see, hum - can i just use this 'double' snispet, deduplicate it as many times as needed, and just change the C type
<daviid>flatwhatson: ok, i'll do that then, and test - i only need to cover the ffi types
<flatwhatson>yep that should be fine
<daviid>ok, many thakns again, i'll try that and get back when done ..
<flatwhatson>i will say though, i think this stubborn approach not using libguile is a big mistake, there's a non-negligible overhead in complexity and performance by doing all these trips between scheme and C
<flatwhatson>it could be handled neatly with a single C function returning SCM
<flatwhatson>also that function is writtne for you, ready to copy-and-paste from foreign.c
<daviid>flatwhatson: one more quiz, i decided to go for a naming more like _ffi_pack_double, _ffi_prep_cif ... in my libg-golf C files, then in scheme, i can bind and give them their 'real' name, like ffi-pack-double, ffi-prep-cif ... so i avoid gg_ which does not bring any usefull 'thing' wdyt?
<flatwhatson>names starting with underscore are verboten, reserved by the standard. gg_ prefix brings something useful: an increased chance of not accidentally colliding with other functions in the global namespace
<daviid>flatwhatson: right, but i only have a few lines of C code so far, really, if i only use 10% of the g-golf C code it's a lot, we are talking about say, les then 50 lines of real C code so far, and mostly to get the size of 'something', or access to a gobject macro (not even sure i still ffectibvely us those ... )
<daviid>our phrases are overpassing each other, but i follow ...
<daviid>what about postfixing then
<daviid>for some reasn, i don't like the gg_ :)
<flatwhatson>namespacing with a prefix is conventional in C. i gave my advice, you're free to make whatever decision
<daviid>ok, thanks
<daviid>flatwhatson: i don't know libguile, but i am (very) surprised you mentioned performance 'problems' - most of g-golf has to use the ffi anyway, absolutely every single call you do, no matter what upstream lib you use, uses the ffi - even if i'd use linguile 'here', i'd still have 99.99% of the g-golf code callig the ffi, when playing with gsk, 1000x pewr second ... so i don't see writing an ffi-arg extract for say, 10 types, an overhead
<flatwhatson>yeah, it might not be a significant performance overhead in the whole scope of the application. still it's 2x additional ffi calls per argument to a callback function, with conversion back-and-forth between the C and scheme types
<daviid>what i fail to understand is why the GI team do not provide us with a 'ready' to use ffi-arg exrtaction -> gi-argument - as we all (lang binding) have to rewrite the same C code to paliate the kissing functionality
<flatwhatson>obviously i'm comfortable working in C, and so from my perspective there's no benefit to this back-and-forth when it can be done neatly with one trampoline function in C, as guile itself does.
<flatwhatson>when you're working in the C, you can expect to get your feet wet :P
<daviid>flatwhatson: but, just to make sure i understand, the data transformation still occurs in libguile as well, right? there is no win in using libguile over the ffi in getting a double in scheme (for example)
<daviid>a double from C to scheme, has to be transformed 'no matter what', right? no win in using libguile or the ffi?
<daviid>bbl, have to go afk a few minutes ...
<flatwhatson>the data conversion is the same yes, but you are adding extra conversions for each extra call through the ffi to helper functions
<flatwhatson>eg. with 10 args in your example, you're making 21 FFI calls instead of 1
<flatwhatson>guile is just copying the doubles to convert them, that's not the expensive bit
<flatwhatson>but i think that performance concern might be a distraction, it's likely not significant as you suggested
<flatwhatson>also i think FFI calls for guile are relatively cheap, thanks to its existing tight integration with C. other languages can pay more signficiant performance costs when switching through FFI contexts, so maybe my intuition is off here
<flatwhatson>also, if you had a bytevector-pointer-ref which can read a pointer from a bytevector, you could write all those double-dereference functions in pure scheme, and my argument would be gone :)
<lilyp>but don't you always have two conversions when using anything GValue-related?
<lilyp>or are those two extra conversions induced via girffi?
<flatwhatson>it's for a callback trampoline, libffi just gives you void **args, those need conversion to scheme types to call the actual callback in scheme
<flatwhatson>the implementation being discussed is making an additional FFI call to unpack each void *arg, instead of handling it neatly in one go
<flatwhatson>but it's probably nbd anyway *shrug*
<daviid>flatwhatson: ok, 'the data conversion is the same yes' is what matters for me - the overhead is really (but like really really) insignificant compared to the use of the upstream lib to actually write/excute a real app ... - then this bytevector-pointer-ref, could you pseudo code expand a bit, i don't see why i could not write it ...
<daviid>flatwhatson: i could also write a struct that has a 'slot' for every arg, and fil it in one call ...
<flatwhatson>daviid: something like this (untested):
<flatwhatson>so to unpack a double: (deref-pointer->double (deref-pointer->pointer ffi-arg))
<flatwhatson>oh right, there are bytevector-*-native-ref variants to clean that up
<flatwhatson>actually bytevector-uint-ref could be much neater, one sec
<flatwhatson>daviid: revised:
<Aurora_v_kosmose>Fibers is single-core only isn'it?
<flatwhatson>Aurora_v_kosmose: false, see
<flatwhatson>> By default, Fibers will take advantage of all CPU cores available to it.
<daviid>flatwhatson: ok, thanks, i'll try and expand to other types then ... that soundsway better then 10 to 20 C snipsets
<Aurora_v_kosmose>flatwhatson: Ah, the Go-like mention in the readme & use of "concurrency" specifically misled me.
<Aurora_v_kosmose>That's better than Go-like.
<Aurora_v_kosmose>ACTION rejoices
<flatwhatson>"The Modest Schemer"
<daviid>flatwhatson: guile already has a dereference-pointer
<flatwhatson>daviid: right, even better!
<daviid>flatwhatson: iiuc, i only have to cover C 'usual types', int uint ... and another 1milliond of those :)
<flatwhatson>daviid: there are only 8 variants of ints (8/16/32/64 x signed/unsigned), and two variants of floats
<daviid>flatwhatson: right, so now i can even keep everyting in scheme, my goal, when possible ofc
<flatwhatson>yeah i agree if it can be 100% scheme that's better
<daviid>i am actually quite 'proud' that my callback marshaler is entirely written in scheme, and also, it made it work so it covers not only callback, as in GIFunctionInfo arguments that expect a callback, but for Vfunc - no other lang binding does that, they all write 2 callback machanism, and in C ...
<haugh>I don't know C. I'm well on my way to making Guile my primary language, and as I get comfortable with Guix I really can't imagine shipping infra with anything else long-term. Am I making a big mistake by continuing to neglect C? My reasoning is that I have no specific goal and I don't need /another/ poorly-defined study path to suck up my time.
<mfiano>I am in the same boat.
<mfiano>I will continue to neglect C
<ane>learn C when you need it, I'd say
<flatwhatson>haugh: no, you only need C if you're hacking on things in C
<flatwhatson>writing FFI bindings to C libraries is one of those things where some C can be handy
<flatwhatson>but those bindings allow everyone *else* to continue to neglect C :)
<jpoiret>civodul, flatwhatson: great, thanks for the feedback!
<jpoiret>civodul: do you want me to add andrew's suggestions?
<civodul>jpoiret: hi! about the doc you mean?
<civodul>looks like i messed up with the doc
<jpoiret>about the doc and the stray comment yeah
<jpoiret>but mostly about arguments taking at least one string
<jpoiret>i was thinking about the following:
<civodul>jpoiret: ah sure, i'd welcome fixes for these!
<jpoiret>but should we allow zero or more or one or more arguments? The code currently checks if the list is empty and fails in that case
<civodul>ah yes, i wondered about that too
<civodul>i guess we can allow it but add a warning in the manual saying that most programs expect at list one argument
<flatwhatson>does it make sense to send no arguments ever? i guess you'd find some nice crashes that way
<flatwhatson>zero arguments could default to (list program) instead?
<jpoiret>flatwhatson: but then that would be weird for the user, right? they would be specifying no arguments but it would still pass one
<flatwhatson>yes, true
<jpoiret>i have no strong opinion on this but thought it would be nice to do it the way i wrote it down
<jpoiret>we just have to decide on what to do
<civodul>reading the LWN article i'm not sure actually
<civodul>there's a possibility that Linux will reject lack of argv[0] in the future
<civodul>so we should maybe just leave things as is: requiring a non-empty list
<civodul>actually, reads: "The value in argv[0] should point to a filename string that is associated with the process image being started"
<civodul>it's more restrictive than exec in that regard
<jpoiret>\o/ that way we don't have to bike-shed anything
<flatwhatson>but isn't that the same as exec? it *should* be the file, but actually it's up to the caller
<civodul>well it doesn't invite you to have argv[0] = NULL anyway :-)
<flatwhatson>sometimes a custom argv[0] is used to tag processes, as with "exec -a some-name ..." in the shell
<flatwhatson>anyway i'm happy with null arguments giving an error, anything else is footgun territory
<jpoiret>i'm not talking about enforcing argv[0] to be the exact file name (and it's often not exactly that), but to at least be present
<jpoiret>exec can actually take empty argument lists, but posix_spawn cannot
<civodul>ACTION is back
<civodul>jpoiret, flatwhatson: so i think we agree on keeping the non-empty-argument-list test, right?
<flatwhatson>yes from me
<jpoiret>yes also for me
<lloda>'A bytevector is a raw bit string'. Shouldn't that be byte
<apteryx>is it me, or the doc of fold is not accurate?
<apteryx>it doesn't explain what is kons or knil
<lloda>Returns the next byte available from the binary input port @var{in},
<lloda>sorry :-/
<lloda>apteryx: does explain what knil (init) or kons (proc) are
<lloda>but there used to be a built in version of this so maybe there's older doc somewhere
<apteryx>I'm using ,d fold from the repl
<apteryx>hm, the ,d says see the manual
<apteryx>fair enough
<lloda>yeah that is incomplete
<lloda>would be nice to have enough to remember if it's (kons ... knil) or (kons knil ...) at least
<lloda>i used to forget that all the time
<apteryx>actually, what I really used is Gesier, not ,d fold (C-d d on fold in your source), it shows this:
<apteryx>which left me wondering. but yes at least the manual covers the mysterious kons and knil
<lloda>well that's the same txt just with the module ref. Geiser probably uses (help)
<mwette>looks like you need to start using fold more :)
<apteryx>the manual has the more understandable 'fold proc init lst1 lst2' signature
<apteryx>mwette: hehe, I do!
<mwette>fyi there is also fold-values in (sxml fold) and that is backwards wrt fold
<mwette>backwards in terms of argument order
<lloda>most fold or xxx-fold versions do (kons knil ...) because that makes it more convenient to apply to an arglist. For some reason srfi-1 went the other way
<civodul>ACTION merges wip-posix-spawn in "main"
<mwette>congrat's civodul and team
<old>haugh: Learning C can't hurt you. By learning it, you're closer to the machine and understand some critical things about performance
<old>Some will say that you could learn the same thing with something like C++ and Rust. They are much more complicated beast. C is kind of like Scheme in the sens it's minimal and does not impose anything on its users
<old>If you want to do embedded system or any very low programming you should learn C IMO. It can only benefit your mind
<old>I don't regret it and I wouldn't have been able to complete my master thesis without it :-). + You can read libguile after that to understand Guile's internal!
<old>Little warning though, programming in C is a lot less joyfull than programming in Scheme. But that's true for any language compared to Scheme
<civodul>spawn's in the house! \o/
<civodul>thanks jpoiret & flatwhatson!
<dsmith-work>Happy Friday, Guilers!!
<dsmith-work>Everything old just said about C I heartily agree with
<jpoiret>civodul: incredible!
<jpoiret>thank you very much for your work
<jpoiret>hopefully we'll see some improvements thanks to it
<Aurora_v_kosmose>That's very debatable, the closeness to the machine. Not that it'd be any better with C++ or Rust. But we're mostly not using PDP-11s anymore.
<Aurora_v_kosmose>Memory tiering & caches are entirely opaque to C.
<dsmith-work>True. But you still need to be aware, flushing and invaliding as needs be. (Like when working with DMA)
<old>It's close to the hardware in the sens that I know almost the exact assembly that a memory reference will generate
<old>I can count the number of cache misses for an algorithm that way
<old>I can choose the alignment of every memory allocation and the order the reads and writes are done with membarrier
<old>Ofc if you want bare metal machine, nothing beats the assembly
<Aurora_v_kosmose>That relies on a *lot* of leaky abstractions that, from the point of view of the C spec, are opaque.
<old>yes sure
<old>But in the end, if you're programming for a specific platform, then you're not following the C spec anymore
<old>And the C abstraction is close enough to the machine that you can mentally determine the ammount of cache misses, memory references, possible race conditions very easily
<old>I can't say the same about C++
<Aurora_v_kosmose>That's true, but programmers have a tendency to assume the language takes care of that. And C's growing mismatch with the actual hardware in most cases leads to increasingly large amounts of implementation details for a given platform needing memorization.
<Aurora_v_kosmose>It also kills most portability unless you explicitly ifdef a large amount of your codebase.
<old>typically you put a `arch/` folder like the kernel if you want to support multi-architectures and do not portable stuff
<old>You also need to manage your codebase and the overall architecture of your software in a way that makes it easy to port it to other architectures
<old>It's not trivial, but it has been done
<Aurora_v_kosmose>Well, even just alignment can depend on the platform & memory type. So every struct might need ifdef-ing for ordering.
<old>But I agree on yourp oints
<dsmith-work>C++ is too much magic begind the scenes. C is much closer to 1:1. Not exact, but much closer.
<dsmith-work>When it *matters*, you are probably working with a specific compiler for specific harware.
<Aurora_v_kosmose>Yeah, but like I mentioned, even details that seem fairly innocuous can have performance implications in C. Writing portable C that also performs well is a nightmare.
<old>Define portable
<old>You usually A) do something for an embedded system, which won't be portable ever
<Aurora_v_kosmose>In this case "will run everywhere". The second part is the much harder part.
<old>ah yes that's true
<old>B) Do something Linux specific with Glibc. Which won't be portable ever.
<old>C) You want to target Windows, Android, iOS, macOS, Linux
<old>For C), C++ is probably better
<Aurora_v_kosmose>Yeah. Unfortunately, C tends to be used in many cases where it shouldn't be, because the portability by spec is obvious, but the performance drawbacks aren't.
<Aurora_v_kosmose>And when one tries to write portable & high-performance, you get a /lot/ of conditional compilation & definitions.
<old>Very true
<old>But hey, if you target only Linux like I do, portability is not that hard to achieve!
<old>Except perhaps musl libc
<dsmith-work>I'm getting spoiled by Rust.
<Aurora_v_kosmose>Somewhat, but then do you optimize your datastructures for ARM & RISCV as well? (Ignoring that even different x86_64 platforms can differ in all sorts of ways regarding that.)
<old>It's when you try to port things to weird distros like Void Linux that use musl or to BSD that you find out that your C program rely on a lots of Glibc specific stuffs that are not portable at all
<old>Well it depends. I do dynamic instrumentation for multiple-architectures. So yes I have some very specific structures optimized for the hardware in the critical path
<old>Other structures that are less frequently used are archiecture independant or have a sub-structure that is hardware dependant in it
<old>Not everything has to be optimized down to a cache line :-p
<Aurora_v_kosmose>Ah, so you do. I consider that having to do so manually like that, rather than the compiler handling it by the language not making any guarantees about in-memory representation, is cumbersome.
<Aurora_v_kosmose>Kudos for actually doing it though.
<old>Well dynamic isntrumentation is very low level stuff, so I can't really do without it unfortunatelly. And I need the data representation to be exactly aligned like I want
<old>Otherwise the runtime penalty of instrumentation is too much
<old>But this is a very specific case. Most software developed in C don't go that low at exception of embedded systems
<old>In any case, I believe that learning C is very worth it
<old>even with the advent of new language like Rust
<mirai>is (string-capitalize "64b") supposed to return "64B" ?
<old>mirai: What would you expect it to return?
<mirai>I'd expect it to be 64b, that is, only the first character is changed
<mirai>there's no uppercase for '6' so it should remain unchanged
<old>first character of every words is capitalized
<old>(string-capitalize "b64bc") -> B64Bc
<old>I think by words we mean composed of alphabetic letters
<old>in b64bc we have two words. b and bc seperated by 64
<mirai>(string-capitalize "64b bit bot")
<mirai>$2 = "64B Bit Bot"
<old>in other words, numbers act like whitespace here
<mirai>it does strange things as well
<mirai>(string-capitalize "PL4/i")
<mirai>$3 = "Pl4/I"
<old>Even `-' actl ike so
<mirai>it also lowercases?
<old>(string-capitalize "red-zone") -> "Red-Zone"
<old>so yeah, everything not in [a-zA-Z] act as words separator
<Aurora_v_kosmose>Is (@@ (whatever) some-symbol) really the most reliable way to fetch values from arbitrary unexported symbols in a module, when those values can be autogenerated syntax (or so errors from structure predicates have led me to believe)?
<old>Aurora_v_kosmose: From my experience yes. But something even if the symbol is there in the *.scm, it's not there in the *.go and you can get an error. At least that's what I had at some point
<mirai>I feel like that makes string-capitalize a huge trap to use
<lilyp>I don't
<Aurora_v_kosmose>old: Ah, that's unfortunate, but at least I guess I can stop searching.
<lilyp>if you only want to upcase the first character, that's an easier operation
<Aurora_v_kosmose>The "for debugging only" mention in the manual had me believe there was some better proper way that also had the same capacity.
<old>mirai: Maybe string-capitalize should take an optional argument which is a character set. Every letter in that set is considered a word separator
<mirai>old: note that in the PL example, the L was lowercased
<mirai>that was also a surprise to me
<Aurora_v_kosmose>old: Thanks.
<mirai>lilyp: which operation?
<old>well capitalize means. make it a CamelCase kind of
<old>So lower the letter should be lowered, and upper the others
<old>Aurora_v_kosmose: I don't believe so. Maybe there's a way to evaluate some procedure in the module at runtime, asking for exportation of a symbol? Sounds very ad-hoc and prone to problem
<old>Maybe there's also a way to force usage of the *.scm instead of the optimized *.go to ensure that the symbol is there
<old>It usually work, for debugging. But I had a problem in production where I was using a private symbol of a Guix module. I know that it was there, but I would not access it for some reason
<Aurora_v_kosmose>So @@ might be doing exactly that in the background then, or do you mean that it is itself prone to failure?
<Aurora_v_kosmose>My use-case essentially is that I want to automatically test as much as I can in the module, including procedures I don't plan to import as they're not supposed to ever be used outside of the module.
<old>I see. Maybe there's another way for that instead then.
<old>How about, writing the tests for prive procedure with something like srfi-64 in the module itself
<old>Then, export a single symbol
<old>that will run all the tests
<Aurora_v_kosmose>That's certainly a less gnarly option than what I was currently attempting to do.
<old>In other words, (define-pbulic (%run-internal-tests) (test-begin "this module") (test-eq 1 1) (test-end "this module"))
<old>I think that would do the tricks!
<Aurora_v_kosmose>Although I don't think that's compatible with (unit-test), right?
<old>what's unit-test?
<old>a library?
<Aurora_v_kosmose>Yup. It's part of the guile-library package.
<old>Ah. I don't know it.
<Aurora_v_kosmose>But at the same time, if srfi-64 is now built-in, I suppose porting to that would be worthwhile.
<old>But if you use srfi-64 I'm sure it would work.
<old>Personally I tend to not do unit-testing. I prefer to write high level scenarios that use the public API, trying to maximize the source coverage.
<old>unit-test tend to be too much coupled with the code and I don't like that
<old>But that's just my preference
<Aurora_v_kosmose>I see. In this case I decided for unit testing as I really wanted to exercise all the assertions & preconditions I setup, to cover for all cases of user negligence short of active self-sabotage.
<lilyp>sneek later tell mirai (string-upcase s 0 1)
<mirai>lilyp: thanks
<sneek>mirai, you have 1 message!
<sneek>mirai, lilyp says: (string-upcase s 0 1)
<old>sneek: botsnack
<mwette>haunt wants (system reader); where does that come from?
<old>it's from Guile itself
<mwette>Hmm. In my 3.0.8: ,use (system reader) => "no code for module (system reader)"
<mwette>The test in string-capitalize just looks for non-alpha to alpha transition.
<old>ah no sorry
<old>there's a library guile-reader
<old>used by haunt I think
<old>If you use guix you should get every with guix shell haunt
<dthompson>mwette: (system reader) is in guile-reader
<mwette>srfi-13 defines string-titlecase to upcase if prev is not uppercase; maybe guile string-capitalize could upcase if preceeded by whitespace otherwize downcase
<dthompson>if you don't guile-reader when you run ./configure, it should disable Skribe format support.
<mwette>Got it. I think it complained when I ran the example.
<mwette>and guile-reader configure complains about not having guile > 1.8, haha; I'll wait to chase that down
<dthompson>mwette: ah right the example is my integration test where I have everything enabled
<dthompson>feel free to locally delete the skribe files
<dthompson>or whatever other format you aren't building support for
<dthompson>I recommend adding in guile-commonmark so you can use markdown.
<mwette>good --- thanks for the help