jackdaniel changed the topic of #commonlisp to: Common Lisp, the #1=(programmable . #1#) programming language | Wiki: <https://www.cliki.net> | IRC Logs: <https://irclog.tymoon.eu/libera/%23commonlisp> | Cookbook: <https://lispcookbook.github.io/cl-cookbook> | Pastebin: <https://plaster.tymoon.eu/>
ensyde has joined #commonlisp
masinter has quit [Ping timeout: 265 seconds]
masinter has joined #commonlisp
jeosol has joined #commonlisp
NotThatRPG has joined #commonlisp
akoana has quit [Quit: leaving]
Demosthenex has quit [Ping timeout: 268 seconds]
Demosthenex has joined #commonlisp
ensyde has quit [Quit: Leaving]
waleee has quit [Ping timeout: 260 seconds]
Demosthenex has quit [Ping timeout: 252 seconds]
Demosthenex has joined #commonlisp
NotThatRPG has quit [Quit: My MacBook has gone to sleep. ZZZzzz…]
taiju` has joined #commonlisp
taiju` is now known as taiju
xlarsx has joined #commonlisp
xlarsx has quit [Ping timeout: 264 seconds]
wilfred has quit [Quit: Connection closed for inactivity]
chipxxx has joined #commonlisp
causal has joined #commonlisp
wheelsucker has quit [Ping timeout: 244 seconds]
taiju has quit [Ping timeout: 244 seconds]
wheelsucker has joined #commonlisp
wheelsucker has quit [Remote host closed the connection]
wheelsucker has joined #commonlisp
green__ has quit [Ping timeout: 265 seconds]
Colere has quit [Ping timeout: 264 seconds]
Colere has joined #commonlisp
hashfunc has joined #commonlisp
azimut has quit [Ping timeout: 258 seconds]
hashfunc has quit [Remote host closed the connection]
hineios5 has joined #commonlisp
hineios has quit [Ping timeout: 244 seconds]
hineios5 is now known as hineios
rgherdt_ has joined #commonlisp
mingus has quit [Ping timeout: 265 seconds]
rgherdt has quit [Ping timeout: 260 seconds]
hineios2 has joined #commonlisp
hineios has quit [Ping timeout: 265 seconds]
hineios2 is now known as hineios
xlarsx has joined #commonlisp
xlarsx has quit [Ping timeout: 252 seconds]
nexalam_ has joined #commonlisp
nexalam has quit [Ping timeout: 260 seconds]
xlarsx has joined #commonlisp
xlarsx has quit [Ping timeout: 265 seconds]
mingus has joined #commonlisp
sch has joined #commonlisp
sch has quit [Client Quit]
mingus1 has joined #commonlisp
wheelsucker has quit [Ping timeout: 265 seconds]
sch has joined #commonlisp
wheelsucker has joined #commonlisp
chimp_ has quit [Ping timeout: 265 seconds]
mingus has quit [Ping timeout: 260 seconds]
mingus1 is now known as mingus
sch is now known as FallenSky2077
FallenSky2077 has quit [Quit: Leaving]
FallenSky2077 has joined #commonlisp
curious-antelope has joined #commonlisp
curious-antelope has left #commonlisp [#commonlisp]
Cymew has joined #commonlisp
igemnace has joined #commonlisp
ttree has quit [Ping timeout: 264 seconds]
enzuru has quit [Quit: ZNC 1.8.2 - https://znc.in]
chipxxx has quit [Remote host closed the connection]
chipxxx has joined #commonlisp
enzuru has joined #commonlisp
chipxxx has quit [Ping timeout: 265 seconds]
thuna` has joined #commonlisp
epolanski has joined #commonlisp
jeosol has quit [Ping timeout: 252 seconds]
shka has joined #commonlisp
epony has quit [Remote host closed the connection]
wheelsucker has quit [Remote host closed the connection]
wheelsucker has joined #commonlisp
epony has joined #commonlisp
rgherdt_ is now known as rgherdt
aximili has joined #commonlisp
attila_lendvai_ has joined #commonlisp
smudge-the-cat has joined #commonlisp
smudge-the-cat has left #commonlisp [#commonlisp]
Dynom_ has joined #commonlisp
Dynom_ is now known as Guest8698
Psybur has joined #commonlisp
wheelsucker has quit [Ping timeout: 250 seconds]
wheelsucker has joined #commonlisp
mingus1 has joined #commonlisp
mingus has quit [Ping timeout: 260 seconds]
mingus1 is now known as mingus
makomo has quit [Quit: WeeChat 3.5]
wheelsucker has quit [Ping timeout: 252 seconds]
wheelsucker has joined #commonlisp
skeemer has quit [Remote host closed the connection]
serbest has joined #commonlisp
mingus1 has joined #commonlisp
mingus has quit [Ping timeout: 260 seconds]
mingus1 is now known as mingus
azimut has joined #commonlisp
ec has quit [Ping timeout: 258 seconds]
mingus has quit [Ping timeout: 265 seconds]
jmdaemon has quit [Ping timeout: 244 seconds]
ec has joined #commonlisp
mingus has joined #commonlisp
thuna` has quit [Remote host closed the connection]
random-nick has joined #commonlisp
_cymew_ has joined #commonlisp
wheelsucker has quit [Remote host closed the connection]
wheelsucker has joined #commonlisp
makomo has joined #commonlisp
ec has quit [Remote host closed the connection]
waleee has joined #commonlisp
ec has joined #commonlisp
_cymew_ has quit [Ping timeout: 265 seconds]
green__ has joined #commonlisp
thuna` has joined #commonlisp
MajorBiscuit has joined #commonlisp
wheelsucker has quit [Ping timeout: 268 seconds]
wheelsucker has joined #commonlisp
pillton has quit [Quit: ERC 5.4 (IRC client for GNU Emacs 28.1)]
mingus1 has joined #commonlisp
mingus has quit [Ping timeout: 264 seconds]
mingus1 is now known as mingus
<Josh_2> pjb: thanks very helpful :joy:
Josh_2 has quit [Quit: Gotta go fast!]
Josh_2 has joined #commonlisp
tyson2 has joined #commonlisp
<Josh_2> When was last time libraries were added to quicklisp?
<tyson2> Josh_2: as far as I know it happens monthly
<Josh_2> Yes but if you check quicklisp-projects issues nothing has been closed for a long time, plus no updates on planet.lisp
<Josh_2> Xach hasn't responded to issues or put can/cantbuild on them
<Josh_2> This is why I am asking
<Josh_2> I see he has tweets from the 9th
<Duuqnd> lol my filter-maker library is right after the last one to be added
<Josh_2> It would be nice to know what is going on
green__ has quit [Ping timeout: 252 seconds]
epony has quit [Ping timeout: 252 seconds]
epony has joined #commonlisp
aximili has quit [Remote host closed the connection]
<pjb> Josh_2: a few years ago he had some health issues. Perhaps he's again busy with that, or a new job?
attila_lendvai_ is now known as attila_lendvai
jeosol has joined #commonlisp
mingus1 has joined #commonlisp
mingus has quit [Ping timeout: 250 seconds]
mingus1 is now known as mingus
green__ has joined #commonlisp
gateway2000 has quit [Quit: Leaving]
wheelsucker has quit [Remote host closed the connection]
avocadoist has joined #commonlisp
wheelsucker has joined #commonlisp
_cymew_ has joined #commonlisp
cage has joined #commonlisp
aartaka has joined #commonlisp
jeosol has quit [Quit: Client closed]
mingus has quit [Ping timeout: 268 seconds]
waleee has quit [Ping timeout: 268 seconds]
szkl has joined #commonlisp
NotThatRPG has joined #commonlisp
jeosol has joined #commonlisp
MajorBiscuit has quit [Ping timeout: 265 seconds]
Brucio-61 has quit [Ping timeout: 265 seconds]
scymtym has quit [Ping timeout: 265 seconds]
FallenSky2077 has quit [Quit: Leaving]
MajorBiscuit has joined #commonlisp
serbest has quit [Quit: Leaving]
eddof13 has joined #commonlisp
acma has quit [Changing host]
acma has joined #commonlisp
Cymew has quit [Ping timeout: 264 seconds]
green__ has quit [Ping timeout: 252 seconds]
pve has joined #commonlisp
frgo has quit [Ping timeout: 264 seconds]
resttime has quit [Quit: resttime]
karlosz has quit [Quit: karlosz]
green__ has joined #commonlisp
_cymew_ has quit [Ping timeout: 264 seconds]
Brucio-61 has joined #commonlisp
green__ has quit [Read error: Connection reset by peer]
waleee has joined #commonlisp
aartaka has quit [Ping timeout: 265 seconds]
aartaka has joined #commonlisp
NotThatRPG has quit [Quit: My MacBook has gone to sleep. ZZZzzz…]
resttime has joined #commonlisp
MajorBiscuit has quit [Ping timeout: 265 seconds]
scymtym has joined #commonlisp
eddof13 has quit [Quit: My MacBook has gone to sleep. ZZZzzz…]
eddof13 has joined #commonlisp
igemnace has quit [Quit: WeeChat 3.6]
mingus has joined #commonlisp
_cymew_ has joined #commonlisp
makomo has quit [Quit: WeeChat 3.5]
ttree has joined #commonlisp
aartaka has quit [Ping timeout: 260 seconds]
aartaka has joined #commonlisp
eddof13 has quit [Quit: My MacBook has gone to sleep. ZZZzzz…]
orestarod has joined #commonlisp
xlarsx has joined #commonlisp
wheelsucker has quit [Ping timeout: 250 seconds]
wheelsucker has joined #commonlisp
xlarsx has quit [Remote host closed the connection]
xlarsx has joined #commonlisp
waleee has quit [Ping timeout: 252 seconds]
eddof13 has joined #commonlisp
xlarsx has quit [Ping timeout: 260 seconds]
karlosz has joined #commonlisp
makomo has joined #commonlisp
aartaka has quit [Ping timeout: 264 seconds]
makomo has quit [Ping timeout: 264 seconds]
NotThatRPG has joined #commonlisp
attila_lendvai has quit [Read error: Connection reset by peer]
attila_lendvai has joined #commonlisp
MajorBiscuit has joined #commonlisp
jmdaemon has joined #commonlisp
makomo has joined #commonlisp
xlarsx has joined #commonlisp
xlarsx has quit [Read error: Connection reset by peer]
xlarsx has joined #commonlisp
Alfr has quit [Remote host closed the connection]
Alfr has joined #commonlisp
MajorBiscuit has quit [Ping timeout: 264 seconds]
xlarsx has quit [Ping timeout: 252 seconds]
attila_lendvai_ has joined #commonlisp
attila_lendvai has quit [Ping timeout: 264 seconds]
Alfr has quit [Remote host closed the connection]
Alfr has joined #commonlisp
xlarsx has joined #commonlisp
attila_lendvai_ has quit [Quit: Leaving]
attila_lendvai has joined #commonlisp
mekka-tst has joined #commonlisp
kagevf has quit [Quit: Lost terminal]
n1to has joined #commonlisp
_cymew_ has quit [Quit: Konversation terminated!]
tevo has quit [Read error: Connection reset by peer]
_cymew_ has joined #commonlisp
hrberg has quit [Ping timeout: 268 seconds]
tevo has joined #commonlisp
jfh has joined #commonlisp
tyson2 has quit [Remote host closed the connection]
mekka-tst has left #commonlisp [ERC 5.4 (IRC client for GNU Emacs 28.1)]
gxt has quit [Remote host closed the connection]
_cymew_ has quit [Ping timeout: 265 seconds]
gxt has joined #commonlisp
Lord_of_Life_ has joined #commonlisp
Lord_of_Life has quit [Ping timeout: 265 seconds]
tyson2 has joined #commonlisp
Lord_of_Life_ is now known as Lord_of_Life
<mathrick> Shinmera: does the MPG123 segment accept files by content, or does it require a pathname and will always try to open it itself? It's not clear to me from reading the docs and source
Catie has quit [Read error: Connection reset by peer]
waleee has joined #commonlisp
Catie has joined #commonlisp
Inline has joined #commonlisp
<Shinmera> you mean does it accept an mp3 in memory?
karlosz has quit [Quit: karlosz]
eddof13 has quit [Quit: My MacBook has gone to sleep. ZZZzzz…]
<mathrick> Shinmera: yes
<Shinmera> It uses the wrapper interface, which only supports files.
<Shinmera> Fwiw mp3s are a bad idea for games. They're slower to decode, don't loop smoothly, and aren't great for short effects aynhow.
<Shinmera> For sfx using wavs is fine, and for music ogg/vorbis streamed is also fine.
<mathrick> ah, do those segments support in-memory input data?
<Shinmera> wav has an in-memory source
Inline has quit [Quit: Leaving]
<Shinmera> (which reads the file into memory for you)
<Shinmera> and the vorbis source accepts pointers or octet vectors as a "file"
<mathrick> ah, OK, that's workable
<Shinmera> are you already concerned about Io latency or why are you asking?
tibfulv has quit [Remote host closed the connection]
tibfulv has joined #commonlisp
<mathrick> Shinmera: because having to specify paths on the local filesystem is really constraining for the rest of the design
<Shinmera> is it?
<Shinmera> :)
<mathrick> yes! It's really convenient to have the option of having the library open a file for you, but it's really inconvenient if that's the only way you have to talk to it
<Shinmera> I haven't felt any constraints
gxt has quit [Remote host closed the connection]
gxt has joined #commonlisp
attila_lendvai has quit [Ping timeout: 252 seconds]
<Shinmera> And anyway, please don't feel like this is closed source software. Everything is there and can be adapted should the need arise.
<mathrick> sure, was just feeling around :)
<mathrick> but I also wanted to know ahead of time, because I don't think I've ever used a library for longer than the tutorial without wanting to use in-memory sources, so it's one of those API corners I explore immediately
<Shinmera> any source in cl-mixed can pretty trivially be turned into an in-memory source, anyhow.
<mathrick> howso? I thought they'd need to serve uncompressed samples for the rest of the segments to be able to consume them?
<Shinmera> indeed. So you uncompress them :)
eddof13 has joined #commonlisp
<mathrick> right, but that would require using the underlying decompression library, which in the case of mpg123 at least isn't supported I thought?
<Shinmera> I mean, you read it from file into one uncompressed pack buffer. and then you just use that pack as a source.
<mathrick> right, meaning I'd have to make my own decoder segment, correct?
<Shinmera> no, why
<mathrick> maybe I'm getting confused about how the segments work here
<Shinmera> a source segment just outputs stuff into a PACK when MIX is called. So you attach a PACK that's big enough to contain all the data, attach it to the source, call MIX, and you got all the data uncompressed and decoded in-memory.
<mathrick> OK, I'm still getting used to the terminology used in cl-mixed
<Shinmera> all you need to do then is attach that pack to an unpacker segment.
<Shinmera> by default harmony takes care of buffer and pack allocation for you, sizing things in accordance to its internal samplerate and buffer length.
<Shinmera> but there's nothing stopping you from doing a thingy before hand or manually managing stuff outside harmony.
<mathrick> ah, OK
<Shinmera> A feature I haven't tested yet is even providing your own malloc/free for libmixed to use so you could have it allocate everything in a static-vector or something to keep things lisp-side.
<mathrick> yeah, that does sound nice :)
cage has quit [Quit: rcirc on GNU Emacs 27.1]
<gin> is there a more elegant way to do this? (if (zerop (length *a*)) "" (concatenate 'string "prefix: " *a*))
<gin> or is what I have written just fine?
<gin> I am trying to return "prefix: " followed by the string only if it is non-empty string. If it is an empty string, just return the empty string.
<mathrick> gin: is *A* a list or an array/string?
<gin> a string
<Shinmera> (format NIL "~@[prefix: ~a~]" *a*)
<Shinmera> ime format is always shorter than concatenate.
<_death> almost.. (defun nonempty-string-p (x) (if (equal x "") nil x)) then pass (nonempty-string-p *a*) to format
<thuna`> Shinmera: isn't an empty string considered non-nil
<Shinmera> ah, true.
<gin> _death: wouldn't that return NIL instead of "" for empty string?
<Shinmera> I often have a handy OR* that treats empty strings as NIL, so with that it would be (format .. (or* *a*)) :)
<_death> gin: that's the intent
<gin> there is an OR*? I can only find OR documentation on clhs
<mathrick> that's a wrapper you write yourself
<mathrick> or helper I mean
gateway2000 has joined #commonlisp
<thuna`> I thought there was a format directive that checked for equality between its arguments but am I misremembering?
<Shinmera> (format NIL "~[~;prefix: ~a~]" (length *a*) *a*)
<Shinmera> would be another variant
<Shinmera> err, nvm
<Shinmera> that doesn't work beyond length one darn.
<thuna`> It's (format NIL "~[~:;prefix: ~a~]" (length *a*) *a*) I think
<thuna`> (~; changed to ~:;)
Guest8698 has quit [Quit: WeeChat 3.6]
<mathrick> FORMAT's language is as useful as it is cryptic and obscure :)
<Shinmera> thuna`: ah, nice. never had to use that before.
<Shinmera> alternatively: (format NIL "~:[prefix: ~a~;~]" (string= "" *a*) *a*)
<thuna`> Shinmera: At that point, don't do it :)
<Shinmera> (I've always hated how the order is flipped for ~:[ from what I expect it to be)
<Shinmera> thuna`: it's still shorter than the original!
<aeth> there's some point in complexity that's sooner than most people think but later than I usually attempt where with-output-to-string is a way simpler way to make strings
<mathrick> is there an emacs/SLIME/SLY helper for looking up FORMAT's spec as you write it?
<aeth> (I usually spend about 10 minutes on with-output-to-string, give up, and then do it in a very short FORMAT, but I guess that's better than building a FORMAT that's too elaborate)
<_death> no, but there's C-c C-d ~
<Shinmera> l1sp.org/cl/ understands them, but not M-x hyperspec-lookup :/
<mathrick> _death: ooh, that's already closer to what I had in mind than I expected!
<masinter> is there a slime key binding reference table?
<_death> I had in mind something that pops a small buffer with short directive description as you move around in a format control string
<_death> but that's probably more useful when reading them
<_death> well, there's C-h b or C-h m ... and there's the slime source code
<_death> I'm sure someone also compiled a cheatsheet somewhere
<thuna`> I would be surprised if something like cl-ppcre for format strings doesn't exist already
<_death> what do you mean?
<thuna`> ?
<_death> by "something like cl-ppcre for format strings"
<thuna`> cl-ppcre the package?
<_death> yes, but what about it?
<thuna`> You know, a way to respresent a format string as an sexp
<_death> welp. there's (macroexpand-1 '(formatter "insert ~A here")) ;) .. but then there's http://cs-www.cs.yale.edu/homes/dvm/format-stinks.html and derivatives
<_death> indeed it could be (out (:q ((alexandria:emptyp x) "") (t "prefix: " x)))
xlarsx has quit [Remote host closed the connection]
<_death> or (out (:q ((not (alexandria:emptyp x)) "prefix: " x))) I guess
xlarsx has joined #commonlisp
rgherdt has quit [Remote host closed the connection]
tyson2 has quit [Remote host closed the connection]
karlosz has joined #commonlisp
xlarsx has quit [Ping timeout: 244 seconds]
Alfr has quit [Quit: Leaving]
klm2is has joined #commonlisp
xlarsx has joined #commonlisp
hashfunc has joined #commonlisp
xlarsx has quit [Ping timeout: 264 seconds]
epolanski has quit [Quit: Connection closed for inactivity]
shka has quit [Ping timeout: 265 seconds]
xlarsx has joined #commonlisp
Alfr has joined #commonlisp
NotThatRPG has quit [Quit: My MacBook has gone to sleep. ZZZzzz…]
xlarsx has quit [Ping timeout: 252 seconds]
MajorBiscuit has joined #commonlisp
xlarsx has joined #commonlisp
n1to has quit [Remote host closed the connection]
xlarsx has quit [Ping timeout: 252 seconds]
pve has quit [Quit: leaving]
<gin> (let* ((a 10) (a 20)) (print a)) ; <= this prints 20. is there anyway to access the outer a = 10 within LET*?
<_death> no
<aeth> yes
<aeth> (let* ((a 10) (a (* 2 a))) (print a)) ; accesses the outer a
<thuna`> Does "within LET*" mean SPEC or BODY
<aeth> that's the last point at which that is possible
MajorBiscuit has quit [Ping timeout: 264 seconds]
tyson2 has joined #commonlisp
eddof13 has quit [Quit: My MacBook has gone to sleep. ZZZzzz…]
euandreh has quit [Ping timeout: 268 seconds]
sjl has joined #commonlisp
xlarsx has joined #commonlisp
euandreh has joined #commonlisp
xlarsx has quit [Ping timeout: 264 seconds]
<mathrick> _death: FORMAT is extremely useful. That page is essentially cout for CL, and there's a reason cout is widely regarded to be toxic. No matter how cryptic, format strings are always superior to alternatives, and it's precisely the fact that they separate the printing code from the specification of what to print and how
<mathrick> OUT, cout, and anything else that builds strings immediately in the code cannot be localised
wheelsucker has quit [Ping timeout: 268 seconds]
wheelsucker has joined #commonlisp
hashfunc has quit [Remote host closed the connection]
<_death> heard that one before.. but look, lisp code can easily be treated as data, and vice versa
<_death> also, I recommend not think of an OUT operator as something as simplistic as std::cout
xlarsx has joined #commonlisp
<aeth> 50% of the hatred for cout comes from the overloading of << which is irrelevant here
<aeth> if you're generating strings in a complicated way, then odds are you're generating HTML (or similar), and you don't have to localize "<html>" into other languages, just the body text, which can be done at another step
<mathrick> _death: but it's exactly that. It's a macro that expands to code that builds strings out of little chunks, which is exactly what cout does as well, << and "type safety" notwithstanding
<jcowan> someone might want to adapt Scheme's SRFI 166 to CL; it provides formatters based on a monadic combinator, but you don't have to know it works to use it:
<jcowan> (define (print-table-of-contents alist)
<jcowan> (each (car x) (space-to 72) (padded 3 (cdr x))))
<jcowan> (define (print-line x)
<jcowan> '(("An Unexpected Party" . 29)
<jcowan> (show #t (with ((pad-char #\.))
<jcowan> (joined/suffix print-line alist nl))))
<jcowan> (print-table-of-contents
<jcowan> ("A Short Rest" . 87)
<jcowan> ("Roast Mutton" . 60)
<jcowan> ("Over Hill and Under Hill" . 100)
<jcowan> ("Riddles in the Dark" . 115)))
<jcowan> (sorry, clicked the wrong button)
<mathrick> aeth: sure, it's possible to *abuse* FORMAT. But OUT is not a solution to a problem that needs to be solved, and certainly not in the way OUT proposes
xlarsx has quit [Ping timeout: 265 seconds]
<_death> mathrick: we can start with the fact that std::cout is not a (lisp analogue of a) macro..
<mathrick> but that's irrelevant. It does the exact same thing in the exact same way
<mathrick> modulo irrelevant details that don't change the picture in any meaningful way
<aeth> you can use whatever you want to generate the FORMAT string, though, if you really need to do "a whole lot of formatting | Hello, ~A | a whole lot of formatting"
<mathrick> FORMAT, printf, str.format, or whatever $language uses is the right way to do human-oriented string output
<aeth> no reason to use a very fancy FORMAT or to use a FORMAT to generate a FORMAT
<mathrick> OUT, cout and other contraptions that build them out of little chunks are just not
<_death> a format control string also specifies little chunks, so I'm not sure about that point.. anyway, my experience with an OUT macro suggests that it's not difficult to do whatever it is you want to do with it, although I don't think I needed to localize such forms
<mathrick> no, it specifies the entire thing at once. Which means it can be localised, preserving all the context that's possible to preserve, and allowing the pieces to be reordered, which is critical for proper localisation
<aeth> In the very real example of generating "<!DOCTYPE html>~%<html lang="en">~%<head><title>Hello!</title></head>~%<body><p>Hello, ~A!</p></body>~%</html>" you only need to use a FORMAT string at this point and at no other point (except, of course, the whole body text is ~A, not just the name in the hello world), and can use whatever you want to generate the string (at compile time, via some HTML macro)
<aeth> until then.
<aeth> You absolutely don't want to make a mess of it by doing it all in one FORMAT even though you can
<_death> this is wrong, because localization sometimes requires more information than is supplied with ordinary use of format.. it can be information about the arguments, or about the context
<mathrick> yes, HTML "strings" are a very different use case, and you should be using a dedicated builder for HTML
<aeth> except in practice, almost all of the time you're generating text, you're generating markup, too
<aeth> because you need to speak to the outside world, and you'd only do that directly in a GUI or in-terminal app.
<aeth> almost all of the text heavy lifting is going to be some form of markup
<_death> so format control strings don't "solve" localization, and they are not the only way to get there
<mathrick> _death: but the typical way to do it already solves the problem! It'll be something like (format nil ($$ "Operation ~A failed due to ~A" :context "File save") ... ...), where $$ is the "look up localised string" function
<jcowan> anyway, this is what comes out:
orestarod has quit [Ping timeout: 264 seconds]
<mathrick> and for numeric values, you'll typically have a second variant of it that is informed that a certain value is a count / ordinal, and can localise it according to the language's rules
<mathrick> so you don't have ugly stuff like "~D file(s) deleted"
<mathrick> which isn't even possible in many languages the way it is in English
<aeth> this seems like such a small part of the overall string processing, though.
<mathrick> it's the one programmer routinely fuck up though\
<_death> (outs (:$ "Operation " op " failed due to " reason (:context "File save")))
<mathrick> I've spent a lot of time in localisation, and almost everyone gets it wrong, especially if they have "oh, you don't need anything special, and it's a minor thing anyway" attitude
<aeth> mathrick: that only happens if you don't separate text (user visible text) from strings, though
<_death> note that in your format control string, the order is implied
<mathrick> _death: yeah, I'm looking forward to you extracting this to a single text file the translator can edit to get all the strings translated
<_death> while in my expression, the arguments are named
<mathrick> because that's what happens with FORMAT-style strings
<mathrick> aeth: but OUT is built *for* building user-visible text! That's what the author advocates it for with the very first example!
<mathrick> not HTML
<mathrick> information for the user
<aeth> You could do something not unlike gettext. A reader macro where you write the English (or whatever the original language is) and then that's actually looking up the translation. _"Hello, world!"
<mathrick> _death: you can give them explicit positional values if they get reordered
<aeth> Except #_"Hello, world!" is more Common Lispy
<_death> mathrick: why is your translator editing a text file? isn't it better to have a program with a GUI that can be a bit more ambitious with regards to localization work
<mathrick> aeth: yes. And gettext() relies on there being a single string. They even have a document explaining why printf() is better than cout :)
xlarsx has joined #commonlisp
<mathrick> _death: does not matter. The input still needs to be some data format
<aeth> You don't even want real format strings, you probably just want ~a and ~%
<aeth> mathrick: everything user visible should be a real string, that's it
<aeth> anything where the order can change (so any prose)
<mathrick> if you have (outs (:$ "Operation " op " failed due to " reason (:context "File save"))), there are references to lexical values of OP and REASON
<mathrick> those can't be extracted
<mathrick> aeth: I don't really understand what you're saying
<_death> mathrick: of course they can?
<aeth> _death: Not in a simple way like gettext
<_death> I'm not talking about gettext
<mathrick> it seems to me that you're advocating for how FORMAT does things, whilst also saying that it doesn't have to be that way?
<_death> what I'm saying is that Lisp is not C or C++, so people need not judge localization issues with an OUT operator in the same way as with std::cout or the likes
<mathrick> _death: OK, so your OUTS boils down to FORMAT and building the format string dynamically under the hood?
<_death> not necessarily
<mathrick> like, how does it actually *work*
<aeth> mathrick: You're saying that FORMAT shouldn't be used over alternatives because of localization, while I'm saying that only the part of the string that needs to be localized (which is a tiny, tiny, tiny portion of actual string processing in practice) needs to be localized and can be done so as a reader macro like #_"Operation ~A failed due to ~A~%" which freely composes with just about any way to
<aeth> generate output.
<aeth> You probably shouldn't even let that macro let you do 95% of what FORMAT can do
<mathrick> _death: cool. Can you show me what the extracted localisable text would look like with it?
<aeth> s/that macro/that reader macro/
<aeth> although I suppose if it has arguments you have to use the longer form #_("Operation ~A failed due to ~A~%" op reason)
xlarsx has quit [Ping timeout: 264 seconds]
<_death> mathrick: like I said.. I didn't use it for localization.. if I would, I'd have some out-operator like I gave in the conversation.. out-operators have the full power of lisp macros
<mathrick> aeth: 1) user-facing text is a big part of FORMAT usage in practice 2) not just "the text", but also all the references to the values interpolated into it. Most text show to the user is not static
<_death> so the expression, possibly annotated, could be stored and a tool could be written to work with it and let users specify localized descriptions, which can be used at runtime
<mathrick> _death: yeah, but I want to know how your "some operator" achieves that feat. Because with FORMAT, it's very easy and a solved problem essentially. The biggest hurdle in Lisp are actually the macros, because it means you don't always see the calls to FORMAT / gettext-like operator to know what all the strings of interest are
<mathrick> but other than that, it's a very straightforward thing to do
<aeth> mathrick: (1) By volume, HTML and similar is probably the vast majority of string output and (2) FORMAT does a lot of things that you probably shouldn't do so even if it looks like FORMAT, it isn't. Of course, it could be implemented via FORMAT, but then you'd have to parse all of the ~s first to make sure that it removes almost all of the feature set.
<mathrick> with your "some operator", I don't even have a sketch of how it could possibly work
<_death> mathrick: unfortunately I've no plans to design such an operator at this time
<aeth> In principle, _death's s-expression based translation macro faces the same problem that translations in a FORMAT-style string face: the word order can change from the English.
<aeth> So that would need to be solved either way.
<aeth> Perhaps the only valid way to write our trivial example in another language is (reason op) not (op reason)
<mathrick> aeth: actually, aside from the English-specific stuff like plurals, the things in FORMAT that seem like it's too much are good for localisation. Because it means you can keep more of it together, in the context, to generate something that will actually read OK in the target language
<mathrick> list processing and conditionals are good for that
<_death> aeth: like I said, it's in fact easier because the arguments are named and not positional
<_death> it's also easier to extend than format's ~/ and the extension can be more powerful
<_death> so you can create a meaningful language tuned for localization
<mathrick> that sounds suspiciously like "cout is better because it's type-safe!" (whatever that means). I'll believe it if you can show me even an outline of what that would actually look like for even the simplest example here
<_death> it comes down to the fact that when you want localization, a format control string is a useful hack, not an actual thing that was designed for localization
<mathrick> but the thing is, if you want a solution that's good for localisation, format control strings are in fact just about the best design you can come up with. They weren't written with localisation in mind, but they are still more or less the best practical solution anyone's come up with
<_death> well, again.. std::cout does not get to analyze its full expression, and C++ programmers don't usually programmatically analyze their source to do that
<mathrick> well, again... please show me what OUT's output would look like for localisation
<mathrick> you say that it can be done, but I still have no idea what possible shape it could take
<mathrick> other than "it's more powerful"
<_death> not in the mood for writing a poc now
<aeth> mathrick: _death just brought up another feature that absolutely needs to not be available in a translation DSL, ~/
<mathrick> at least a snippet of pseudocode would be nice :)
<aeth> mathrick: and I'm sure if this conversation goes on long enough we'll have a very long list of FORMAT features not to include
<aeth> best just to whitelist it and stick to ~A and ~% for now. Especially since you can just compose (at the cost of efficiency) stuff like ~F
<_death> if I'll need to write a localization operator sometime, I'll let you know if you're around ;)
nexalam__ has joined #commonlisp
<mathrick> _death: sure, I'd love to see it! If you can extract the info in a way that can be fed back into the code at runtime, that would be amazing and indeed more powerful than FORMAT
nexalam_ has quit [Ping timeout: 260 seconds]
<_death> sometimes I think such requests for localizable output should just be (some-identifier :x 42 :y 123 :z 165)
<_death> then you don't need to hardcore some message in the code (by default you can even just print the list :)
<_death> that of course moves the issue of translation representation elsewhere
<Alfr> _death, s/some-identifier/#:g72/g
<Alfr> _death, just to make sure you don't associate to much information with it.
<_death> no, it needs to be a bonafide symbol with a home package
<aeth> That's easy, all you need to do is translate "Guru Meditation" and then everything else is just a bunch of hex
<Alfr> _death, just say, it's printed output, not something you could reasonably expect to be useful after reading.
<mathrick> _death: you'd still need to come up with a way to get the values into the string, which needs to happen through some sort of code
<_death> you can have some-identifier associated with (:language english :format "~A+~A=~A") or (:language english :out (:x "+" :y "=" :z)) .. in both cases these are interpreted (or compiled) at runtime
<mathrick> for all its problems, gettext gets it right: translators just get more or less inert text to work with
<mathrick> but if SOME-IDENTIFIER needs to know itself how to get the values into its text, then you end up with Win9x style of localisation, where each language was a separate set of DLLs, and they were not compatible with each other
<Alfr> mathrick, I'm not certain it's a good idea to give translators only "inert" text; sometimes you really want to switch your arguments around as a translator.
<_death> (that :format should probably include :x :y :z)
<aeth> assuming you're in COMMON-LISP-USER and you use some TO-UTF8 function, then: (format nil "GURU MEDITATION ~{~A:~A~}" (mapcar (lambda (string) (format nil "~{~2,'0X~}" (coerce (to-utf8 string) 'list))) (list (package-name (symbol-package 'foo)) (symbol-name 'foo))))
<aeth> which becomes "GURU MEDITATION 434F4D4D4F4E2D4C4953502D55534552:464F4F"
<aeth> there you go, no need to translate
<mathrick> Alfr: yes, I know, that's what I've been saying :)
<_death> mathrick: I didn't mean some-identifier is an operator.. it's just data that's passed to the request for localized output, like (out (:l some-identifier :x 42 ...))
<mathrick> aeth: heh, that's a great replacement for "Are you sure you want to close file 'foo.txt' without saving? It was last saved 2 hours 45 minutes ago and has been edited 17 times since"
<mathrick> _death: so it would have to be interpreted by some sort of string-specific interpreter afterwards, no?
<_death> why string-specific? an interpreter that builds up a string, maybe
<mathrick> which is pretty much what FORMAT / printf are. A specialised interpreter for a very limited (or not so much in the case of FORMAT) embedded language
<_death> right, but the format control language is not designed with localization in mind
<mathrick> _death: for the same reason aeth wants to exclude ~/ from the language understood by the localisation, since it can open you up for arbitrary code injection
<_death> and it's not easily extensible for such purposes
<mathrick> so it needs to be string-specific
<mathrick> and limited
<_death> well, I don't immediately see why it needs to protect against "arbitrary code injection" or be limited.. but it could if you wanted to constrain it that way
<mathrick> because localisation shouldn't crash your code and allow people to steal credit cards :)
<mathrick> so if we're talking localisable text that you ship off to people who aren't necessarily programmers, then it's a useful/necessary constraint to have
<_death> if you trust it enough to display something to the user, it is possible that such trust extend to running code
<mathrick> that is actually already the case with gettext() in C, it can crash if the localisation messes up the arguments
<_death> if you just have a translator wiki that anyone can edit.. sure, probably better to constrain :)
<Alfr> mathrick, if you localize and ship yourself, then the format string isn't of concern. (Unless you're malicious.)
<Alfr> mathrick, I.e. load the translations into the image and don't ship them separately.
<aeth> mathrick: sure, you can add seconds since last edit and the number 17 to the end, space separated, too :-p
<mathrick> aeth: OK. How do you do that in a localisable way? :P
<mathrick> we've just come full circle
<mathrick> Alfr: that's again a lot like the win9x way, which wasn't great. I like the fact that I can install arbitrary languages for my apps through apt and it just works. Localisations are not of trivial size once you're starting to talk 95+ different languages for something the size of Firefox or Libreoffice
<_death> anyway, it reminded me of old parmenides (a project from 1990) localization approach.. it uses format control strings too.. https://github.com/death/Parmenides/blob/master/src/frk/fr-messages-esp.lisp
<mathrick> yeah, that's pretty much gettext, except the string itself is not used for lookup
<_death> and I just noticed line 74 there..
<Alfr> mathrick, not that size itself is really of concern, producing the text is cost prohibitive enough that you won't do that.
<Alfr> mathrick, assuming the king of information you want to output is fixed, associating with every tag a permutation will get you very far already.
<Alfr> s/king/kind/
<mathrick> Alfr: not sure I get what you're saying. Won't do what?
<mathrick> _death: heh, yeah. FORMAT certainly wasn't made *for* localisation, but it does work for it if you stay away from ~:R and its ilk
<_death> sure, it works.. up to a point ;)
<mathrick> oh man, I forgot that FORMAT can not only do Roman numerals, but also old Roman numerals
ec has quit [Ping timeout: 258 seconds]
<Alfr> mathrick, I'm saying there, that the "size" localizations use don't matter.
ec has joined #commonlisp
<_death> anyway, localized output is not the only output a program my generate.. for example I used OUT to generate (non-lisp) source code in adhoc semi-structured way
<_death> some years ago I talked about it in this channel and pasted https://gist.github.com/death/4e273d14e671a3c64f3be10cab2aa1b2
JamesF has joined #commonlisp