freenode/#lisp - IRC Chatlog
Search
9:29:41
jackdaniel
but before I even start to work on that higher on the stack are: green threads and delimited continuations (I have a working prototype locally), compiler refactor for different backends and fast gf dispatch
9:33:28
elderK
makomo: I think I finally understand! At least, I was able to write my own once-only!
9:34:10
elderK
I wrote the usual pattern that we use gensyms with. Then I thought, right, how do I generate that?
9:34:29
elderK
Then there's the business of remapping a or whatever to the gensym, so when the body says ,a it's really referring to the gensymed stuff.
9:34:46
elderK
Once I wrote the expected expansion in a normal macro, I then worked backwards from that to try and replicate it.
9:35:32
makomo
yup, that is a very good approach to developing macros imo -- you see a pattern (i.e. start from an example) and try to abstract it
9:35:33
elderK
makomo: So, I have learned for instance that ``(,,a) -> `(,b). I.e. we have two ,,s so we're going to patch something in. But we only replace the ,a, not the entire ,,a
9:35:58
elderK
I was confused by seeing ,,@(....). But I figured out that it makes sense: Whatever is spliced in, the , kind of distributes.
9:36:36
elderK
Then I learned that ,`(.....) is basically a nop. It just means "Carry the thing after the , into the expansion, verbatim."
9:36:51
dim
I have once again a bug report containing: There is no applicable method for the generic function #<STANDARD-GENERIC-FUNCTION PGLOADER.CATALOG:FORMAT-TABLE-NAME (1)> when called with arguments (NIL).
9:36:59
elderK
So for ,`(,b) well, the next level just has the (,b). When that's expanded, the value of b will be chunked in, etc.
9:37:27
elderK
makomo: I wound up doing some "silly things" like color-coding parts of the macro, to highlight "when things actually do shit"
9:37:29
dim
I'm fed up of having those function calls with a NIL argument where it should be an instance of something, usually that's because I'm using find or the like and it didn't raise any result
9:37:40
elderK
Mentally, it's still a little fuzzy. But it felt like jumping between realities :P lol
9:37:52
dim
is there in CL an approach like the Maybe option type that would help systematically address the NIL propagation>?
9:38:55
elderK
:P Or it could just be that I've memorized PCL's version. I guess I'll try again in a week or so and see if I realy CAN do it from basics without referring to PCL :D
9:39:39
elderK
It's not returning null. It's basically returning a value wrapper. You can get the result from that, or say : Oh, it's null.
9:39:53
jackdaniel
elderK: this doesn't tell me much (I knew some C++, but it could be before this option was introduced)
9:40:21
elderK
Okay, well, imagine you have a wrapper. This wrapper can store a value of whatever. BUt it also has a flag that says whether it stores something ATM.
9:40:39
elderK
So, instead of returning null, you return an instance of this wrapper. And you can ask it: Hey, do you have a value?
9:40:59
elderK
It's useful in situations where "null" is not a good error return value, because it would be a valid result, say.
9:42:30
elderK
One benefit, at least in C++, is that it also adds a sense of assurance. Let's say you return some NULL and use it without checking. Well, you're going to crash MAYBE at some point. Depending on waht happens.
9:43:48
dim
jackdaniel: it's basically a way to say that if you receive NIL as an argument, just return NIL already
9:44:20
dim
in PostgreSQL you can also create function x(...) returns ... return null on null input ... ; which does the same thing, conceptually
9:44:38
jackdaniel
another approach would be using filtered-functions which add preprocessing step to generic functions
9:44:49
dim
well because I would have to do that for a lot of generic functions, and then I have to check that every call point knows how to handle NILs too, etc etc
9:47:20
jackdaniel
yes, this maybe operator looks like a common lisp type which is not a class, and you can't specialize on such types
9:49:02
jackdaniel
dim: closest thing to handle such thing would be using filtered-functions, but I'm not sure if it buys you anything
9:50:04
Bike
conceptually it would be a class; the Maybe's equivalent to "nil" is a distinguished value not used for anything else, unlike nil
9:50:22
Bike
then haskell can use static typing information to avoid actually allocating anything when a function returns a Maybe.
9:50:45
jackdaniel
i.e you have a base class foo and two subclasses null-foo and sql-foo and if filtered function encounters nil it calls it with a null-foo instance
9:51:12
jackdaniel
(that way your method specialized on foo would handle proper data and null data when nil is passed there)
9:51:46
jcowan
I've just written implementations of Maybe and Either in Scheme, but not posted them yet: they would be easy to translate into CL
9:52:44
jcowan
jackdaniel: I'm trying to follow the ECL manual's instructions for building an executable. I get as far as calling c:build-program, but that symbol does not exist.
9:52:48
scymtym
but does Maybe automatically make all functions return Nothing when they receive Nothing as an argument? i thought that required Monad lifting or something like that
9:52:51
jackdaniel
Bike: I think that the gist of the problem comes from the fact, that NIL sneaks to the gf call, am I right dim?
9:53:39
jackdaniel
jcowan: did you (require 'cmp) ? also I don't think build-program is exported, you may have better luck with c::build-program
9:54:47
dim
jackdaniel: thanks for introducting filtered-functions, I like that approach... I'm not sure it's useful to prevent the class of bugs I have in mind now, though
9:55:00
Bike
as wikipedia more or less puts it, (>>= mx f) = (if (justp mx) (funcall f (just-value mx)) none)
9:57:10
jcowan
but now when I run the executable my program runs and then drops into the ECL REPL. Is that expected? If I explicitly call (ext:quit) all is well.
9:58:52
jcowan
https://bitbucket.org/cowan/r7rs-wg1-infra/src/default/MaybeEither.md is my docs for the Maybe/Either library
10:01:37
makomo
elderK: although some people don't agree with that (and neither do all of the implementations), but that's why we had that wager the other day
10:02:09
elderK
makomo: Well, it seems if you expand it out the long way, then "collapse" it back into shorthand, you get what looks like distribution.
10:03:17
makomo
jackdaniel: i took a quick look but right now i have 4 exams coming up next week, all 1 day apart. i want to do it properly and make a detailed analysis, but i can't do that without failing my exams :-)
10:04:03
jcowan
Bike: I've specced out but haven't written a general monad library. But yes, without static types you have to pass the monad instance (a struct of functions) explicitly to each monad operation.
10:04:25
jackdaniel
elderK: only sbcl supports ,@,@ and imho it is not portable CL, I've pasted my analysis a few days ago
10:04:44
Bike
i mean, with a cl generic function, it could be done, but there'd be run time checks of course, and you'd have to trust the mfunctions are ok
10:05:58
dim
well I guess in practical terms I have to care everywhere that I don't get a NIL where my code expects something else, and that's going to be a large amount of work because I didn't do that thoroughly from the beginning
10:06:22
jcowan
The trouble with using a gf is that you can only have one monad instance per CL's idea of a class, which is restrictive. When it comes to monoids (which it will), how would you provide both Sum and Product without wrapping numbers in a class, making them unusable as numbers?
10:07:27
elderK
jackdaniel: Thanks jackdaniel :) I was just thinking about it. It would be pretty crazy to see it used.
10:07:42
elderK
jackdaniel: I'll have to consult the CLHS again to see if it's like, iono, disallowed.
10:19:25
elderK
My mental model is the case where '`', ',' and ',@' are just shorthands for operators.
10:20:11
jackdaniel
this discussion was not about intuition but about conforming Lisp code, I can imagine having such intuition
10:21:49
jackdaniel
and last statement (that first two strategies are incorrect) is not well thought through, reader doesn't necessarily return a cons structure, but still third strategy is more convenient and also conforming. either way, conclusion that ,@,@ can't be used in portable code due to ambiguity stands.
10:22:02
elderK
Aye, I see that. You've raised good points. Although, I'm not sure I can fully appreciate those points just yet :)
10:51:19
jackdaniel
https://nullprogram.com/blog/2018/11/21/ (Why Arent' there C Converences, first sentence "Heck, even Lisp has one." linked to ELS ^_^)
10:54:43
jcowan
Bike: You declare two static type synonyms for Number, Sum and Product, each of which can be an instance of Monad.
10:56:45
jackdaniel
yes, I think that was a pretty uneducated sentence (that's why I found it funnY), also you may do more interesting things in Lisp
10:57:52
jackdaniel
it isn't dead, there is just not much to talk about (wrt C) - it is not extensible whatsoever. it evolves though
10:58:25
jackdaniel
_death: well, sentence implies, that it is suprising Lisp has a conference (like as if it is a dead language)
10:58:28
aeth
idk, language popularity measurements are all pretty arbitrary and have wildly different results so I propose the language conference language popularity measurement. ;-)
10:59:50
_death
jackdaniel: maybe it's more about exposing the general readership to the fact that it exists ;)
11:00:31
jackdaniel
I've presented my interpretation of it, I'm not insisting in others agreeing with me, still I found it funny :)
11:01:28
_death
https://european-lisp-symposium.org/2018/index.html look up the author's name under Committee
11:02:51
jackdaniel
alright, I concede it is hard to believe he is uneducated ;) still this sentence sounds (to me) as if he is
11:26:09
shrdlu68
Someone describes something they made as "Written in Rust, a modern, low-level, high-performance language without garbage collection."
11:27:08
jackdaniel
jcowan: it is expected, default value of epilogue-code for :program is `(si::top-level t)
11:27:20
Bike
a language arising from the wide scale and far reaching transformations in western society beginning roughly after world war one
11:27:49
jackdaniel
remember to wrap your toplevel function in a handler-case if you want to avoid suprises
11:28:38
jackdaniel
(i.e unwind-protect not being executed on error which is not handled anywhere up the stack)
11:29:33
jcowan
Bike: I would say that the modern (phase of) languages begins around 1650, at least in Europe.
11:30:17
_death
witten in Common Lisp, an ancient, multi-level, high-inducing language without garbage.
11:32:23
dim
Common Lisp is first of all a very modern programming language for me, even more so when compared to Python, C, Java, PHP, or some others that I've been using
11:34:33
dim
there are so many useful things in the language, in ways that other just can't think about (multiple dispatch, control flow operators, conditions, standard types as classes, interactive debugging by default, running your own code at compile time with defvar/defparameter, and so much more, macros and reader macros of course)
11:35:00
shrdlu68
"Scala combines object-oriented and functional programming in one concise, high-level language."
11:35:06
jackdaniel
i.e things like update-class and elaborate condition handling is something very modern and tailored especially for a lasting solutions
11:35:21
_death
Odin hanged himself upside down for nine days to discover the secret of Common Lisp...
11:36:40
dim
jackdaniel: sometimes I want to play around with LFE (a Lisp on-top of Erlang), where hot code reloading in a distributed cluster is a normal thing to do... ;-)
11:37:26
jcowan
I think it's fair to say that Go, Ada, and Algol 68 are concurrent languages: the concurrency is a language feature, not a library feature. (I grant that this distinction is not very relevant to the Lisps.)
11:38:19
dim
what Erlang guys said is that if you want to have software that runs without downtime, first thing you need is being able to patch it while it's running, because you will have bugs, and specs will change
11:41:11
jcowan
But note that in Erlang the unit of replacement is whole modules, not individual objects, and only one old version is allowed as opposed to an arbitrary number of versions in CL. (Granted, this restriction could be lifted in an Erlang runtime.)
11:51:56
jcowan
Version skew is still a problem even in shared-nothing architectures. I had to make a last-minute patch to my back-end change that added a new key to a JSON request from the front end, because we had to deal with the fact that for perhaps 15 minutes old front ends would be trying to talk to new back ends, which would crap out for lack of the field.
11:52:15
jcowan
The fact that we didn't think of this until the day before release is the disturbing part.
11:58:24
zigpaw
you also have the support for rolling updates in kubernetes - as an example of completly different approach to the zero-downtime problem.
11:58:25
dim
compatibility matrixes, dependencies, ordering pushes to productions of independant components, yeah it's hard
11:59:37
dim
zigpaw: does it solve changing the current state in the application? that's what Erlang is very good about...
12:10:25
shrdlu68
Most codebases not written specifically with that in mind would require significant change.
12:26:59
dim
yeah that's where Erlang is very strong, statefull and hot code reload, plus other things, I really enjoyed using it back when I had to
12:36:09
zigpaw
shrdlu68: yes, as I have mentioned - it is a completly different approach. Inferior in some ways, but that's how other people are dealing with this problem.
12:44:55
pfdietz
jcowan: there is a tension in CL between inclusion of standard functionality, and minimality. The crux there is that all the symbols are visible in a lisp image, and have to be there because they can be obtained by creating those symbols at runtime (by reader or intern).
12:49:58
ogamita
dim: Lisp already has the MayBy type everywhere by default! (defun just (x) (assert x) x) (defun maybe (x) x) (defun nothing () nil)
12:50:45
ogamita
dim: so use (maybe (when (maybe x) …)) but since maybe is identity, just use (when x …) everywhere.
12:51:38
ogamita
and (defmethod numeric-foo ((x null)) 0) (defmethod list-foo ((x null)) nil) (defmethod vector-foo ((x null)) #()) etc.
12:52:24
ogamita
(or of course, you can go get a PhP about why MayBe Just Nothing is needed in Haskell).
12:56:15
ogamita
Bike: Yes, if you want to distinguish bottom false, empty-{list,set,vector,string,thingy}, 0, 0.0, etc from the symbol NIL, yes, you may need a (defstruct maybe x) (defstruct nothing) (defgeneric just (m) (:method ((m maybe)) (maybe-x m)) (:method ((m nothing)) (error "There's nothing!")) (:method ((x t)) x))
12:58:42
ogamita
jcowan: actually, monads can be represented ("are") in CL method-combinations. So you assign each gf to a single monad, and it's independent of the class of the arguments.
13:03:10
ogamita
(actually, a graph of instances, since it's decomposed into components, files, etc).
13:03:51
ogamita
mercourisj: in a way. If you know what a system is, you know where to search for a test whether there's a system accessible in the lisp image.
13:08:32
jackdaniel
when you write cffi:foo reader goes to the cffi package (and it is done at read time)
13:08:52
jackdaniel
so first your read form (and access the package!), then you load the system by executing read form
13:09:49
mercourisj
so (push guix-profile cffi:*foreign-library-directories*) needs to be wrapped in an eval-when of some sort?
13:09:52
jackdaniel
silly workaround would be: (push guix-profile (eval (read-from-string "cffi:*foreign-library-directories*"))
13:10:53
mercourisj
so you said the package is not yet created, (asdf:load-system "cffi"), does that not load the system and symbols?
13:12:26
mercourisj
jackdaniel: so, you're saying the reader does not know of the package CFFI and thus signals an error?
13:13:03
jcowan
ogamita: using nil for Nothing and anything else for Just doesn't work, because you need to be able to say "Just false" and "Just ()" which both come out nil on your formulaton.
13:13:19
jackdaniel
less silly way would be abstracting (symbol-value (find-symbol (string '*foreign-library-directories*) (find-package 'cffi)))
13:16:04
jackdaniel
apparently I'm quite silly myself, because I use read-from-string method couple of times in my lisprc file
13:18:05
jcowan
ogamita: I also don't understand what you are getting at with one gf per monad (instance); it's the monadic operations (map, bind, sequence, join, >>, product, lift) that need to know which monad they are dealing with.
13:18:17
Bike
jcowan: the gethash return values are more of an actual maybe, not that they form a manipulable object
13:19:00
ogamita
You define monads with define-method-combination, and you define operations with (defgeneric … (:method-combination …))
13:19:11
jcowan
I don't know any way to do that in a dynamic language except to pass an object representing the monad. This is what Haskell actually does under the covers for all type classes.
13:19:50
ogamita
With methods combinationsm you don't need to pass it an explicit monad; each gf knows what monad it works in.
13:23:34
jcowan
"Instead of trying to prove your opponent wrong, try to see in what sense he may be right." (Nozack's tolerance principle)
13:23:53
jcowan
The Loewenheim-Skolem theorem guarantees that there will always be such a sense. :-)
13:25:35
jackdaniel
"Instead of treating discutants as opponents treat them as partners. Don't be afraid to 'call bullshit' when applicable." ;p
13:30:34
ogamita
Yes, the difference is in the shifting. Compare mask-field and ldb, it'll be more obvious.
13:32:33
ogamita
(format nil "~8,'0B" (deposit-field #xf0 (byte 4 2) #xaa)) #| --> "10110010" |# (format nil "~8,'0B" (dpb #xf0 (byte 4 2) #xaa)) #| --> "10000010" |#
13:33:54
jcowan
I hit back at Google Groups but so far to no effect (more in c.l.s than c.l.l, to be sure)
13:33:59
ogamita
deposit-field takes (ldb (byte 4 2) #xf0) #| --> 12 |# while dpb takes (ldb (byte 4 0 #|<-|#) #xf0) #| --> 0 |# and both put those bits into (ldb (byte 4 2) #xaa).
14:51:48
jackdaniel
ccl doesn't have condition variables (they are implemented with semaphores on bt), but sbcl and ecl both have broadcast for a condition variable
15:16:51
elderK
Of course it must be a generic function, if you're talking about CLOS and methods and stuff.
15:17:32
elderK
If you're talking about specializing the eql function for other things, I'm not sure how you do that, as it isn't a GF.
15:18:42
_death
you can't specialize EQL.. what is meant is that you can have a specializer that matches when an argument is EQL to an object
15:20:05
_death
in elderK's example, if you pass the ZUG generic function the object THING, then that method is found applicable
15:23:39
elderK
The only other way I am aware of to use "eql" in something regarding types, is with deftype. But I may be mistaken.
15:24:18
mercourisj
I thought you meant somehow modifying the eql function to support comparison between arbitrary object types by writing your own comparator
15:25:24
_death
Inline: there are more sophisticated dispatch mechanism, not part of CL, such as predicate dispatch
15:26:08
jackdaniel
you may read the implementation of filtered-functions to see how you may specialize dispatch mechanism
15:28:23
beach
ACTION wonders what part of "A specializer is either a class or an EQL specializer" was not clear.
15:29:07
jdz
CLIM also has presentation types which I think allows to create finer grained specializers?
15:29:09
jcowan
EQL specializers would be better called singleton or specific-instance specializers imO
15:30:41
beach
jcowan: Perhaps, but that is not what they are called, and it is best to stick to established terminology.
15:30:53
jdz
Right. When I was implementing my CLIM web framework I left presentation types for later, and never got around to doing them.
15:31:11
ogamita
beach: the way brains and consciousness work. The "classic" model, is that you have a lot of agents that detect each one interesting things, and when they do, they try to signal it, but since they compete with all the other agent, only the one or two most vocal agent get to raise above the level of consciousness and can be "reasoned" about.
15:31:53
ogamita
beach: said otherwise, the problem is not "A specializer is either a class or an EQL specializer", it's how a given brain processes it in a given circumstance, with all its other agent competing.
15:32:40
ogamita
beach: this is why sometimes a good "fucking" can help raise the level of a given agent, as in: "A specializer is either a class or a FUCKING EQL specializer"
15:33:02
ogamita
of course, it works only if it's used parcimoniously. Not like in hollywood movies…
15:46:31
elderK
How will I know when I need to use it? :D I figure I'll have a major performance or memory issue. I'll learn a bunch using time and friends. And then, if necessary, I'd use dynamic-extent along with other declarationey things?
16:23:18
ogamita
elderK: it allows to perform stack allocation. You'd use it as often as you'd use alloca instead of malloc… (ie. never).
16:25:14
elderK
ogamita: I was hoping dynamic-extent would be more intelligent than using alloca() in C. Using alloca() in C is okay in some cases but largely, not so much.
16:26:06
elderK
Anywho, that was what I was hoping dynamic-extent could do. Then again, I figure SBCL is pretty smart and at sufficient levels of optimization, will do all of that anyway without being told.
16:26:07
ogamita
It's for the data. Lexical variables are already stored on the stack or in closures.
16:26:11
jackdaniel
elderK: if compiler can prove that they do not escape it will alloc them on a stack either way
16:26:34
jackdaniel
otoh if you declare it dynamic-extent it may take your claim at face value, and given you were wrong - you may fail badly
16:27:05
elderK
In that case, I'll ignore it until you know, one day far in the future, it seems necessary, as suggested earlier.
16:35:18
beach
nirved: No it isn't. She calls the METHOD with an EQL specializer that. But not the specializer itself.
16:36:13
beach
nirved: Since there is no specific term for such a method, neither in the Common Lisp HyperSpec nor in the AMOP, she is free to make up a term for it.
16:36:23
elderK
Out of curiosity: If I cannot specialize a method on a non-class type, like, how do you work around that?
16:36:46
elderK
I've seen some code where they seem to specialize on symbol, and use that to lookup a "metaclass" then dispatch based on that.
16:38:48
beach
elderK: The generic dispatch mechanism is designed to be fast. If you were to allow arbitrary types, it might be arbitrarily slow. Also, the order of applicability may be an issue, since it is not always obvious.
16:39:38
beach
elderK: Using types would basically be a scattered version of TYPECASE. There are libraries that allow you to do that.
16:41:56
beach
It is one of those cases where someone (not you) who doesn't understand much about programming-language design or compiler technology would accuse the creators of Common Lisp of incompetence for the failure of including such things in the standard, and immediately call upon the Common Lisp community to create an updated standard where it IS included.
16:42:01
elderK
beach: Should I be concerned with using find-class? I imagine class lookups are reasonably quick?
16:42:27
beach
You should not be concerned about that. It is a hash-table lookup. But you almost never need it.
16:43:03
beach
It is not as though a method is tested for applicability using find-class every time you call the generic function.
16:43:25
elderK
binary-types find-classes that symbol, and then dispatches to a method specialized on the returned class.
16:44:15
elderK
I'm not sure why you'd want to do that instead of eql specializing on the name, instead.
16:44:45
elderK
Maybe it's a case where like, you have two "binary types" that have different names, but actually are handled the same or something.
16:47:33
beach
elderK: If I were you, I would not be so concerned with the performance of low-level stuff like that. Typically, badly designed algorithms and data structures are the main source of inefficiency.
16:48:44
beach
Of course, it is typical for people (again, not you) who are clueless about efficient algorithms and data structures to worry about micro optimizations, and then completely blow it anyway when it comes to the overall performance.
16:49:53
elderK
People optimizing a loop say, without realizing that the real performance cost is because say, they're using a list instead of something like a tree or hash table :P
16:49:55
beach
Apparently, not even professors of computer science can get a simple thing like binary search right. *sigh*.
16:50:30
elderK
But hey, if you're interested in seeing what I mean by this... uh, pattern? You can find it here: https://github.com/frodef/binary-types/blob/master/binary-types.lisp#L140
16:51:34
elderK
When I was working, I actually had to try and convince my boss, a senior who made way, way more than me, why using a hash table for dispatch would be faster than a 10k some line long if-else chain.
16:53:05
dim
radix tree come to mind, or just, you know, interning the strings in symbols and maintaining a hash-table on the symbols...
16:53:11
beach
elderK: The SIZEOF method should probably normally be called with an instance of a binary type, in which case it is a simple accessor. The method that specializes on a symbol is probably provided for convenience.
16:53:40
jackdaniel
elderK: PCL usage is to be able to find a binary class corresponding to some kind of an identifier (i.e string)
16:55:25
beach
So if you call sizeof not with a symbol, but with an instance of binary-type, which I am guessing is the normal case, then it is a simple slot reader.
16:56:40
elderK
I need to read about the accessors that defclass creates. I am a bit confused as to like, the sizeof accessor.
16:57:14
beach
elderK: It is a generic function with a method that specializes on the binary-type class.
16:58:07
beach
When it says :reader sizeof, it is essentially the same as a method that calls slot-value on the slot. But it is typically much faster than such a method.
16:58:37
beach
So (defmethod sizeof ((object binary-type)) (slot-value object 'sizeof)) or something like that.
17:01:08
beach
elderK: In the past, they were wrong because they would fail in situations such as when the object did not exist, or when there were multiple occurrences.
17:01:08
elderK
At Uni, I saw a lot of people fail when the "sequence" they were binary searching had an even number of elements.
17:01:47
beach
elderK: Not so much now. Now they just fail because they start by testing for equality, which makes them take 50% longer than they should.
17:02:16
elderK
It would be like hashing somewhere in an open-addressed hash table and not checking like, that the thing you've hit is actually what you want.
17:02:43
trittweiler
You shouldn't test for equality at all. That's by definition only true once. It's the uncommon case :)
17:02:50
beach
And if you start by checking for that, you increase the execution time by 50% on the average.
17:04:19
elderK
beach: I'd still like to learn from it all the same, just to avoid making the same mistakes when I work in other languages.
17:06:24
elderK
trittweiler: I'd like to hear about how you deal with say, chained hash tables. I guess you could have a secondary hash and check those as you traverse the "chain" for some primary hash
17:07:41
elderK
beach: I'd agree with you. I've been surprised by how often I've seen implementations of say, search trees, that perform comaprisons more than necessary.
17:07:54
elderK
although I guess that's a different kettle of fish, I still feel it should be avoided at all costs.
17:07:56
trittweiler
The other thing is that binary search should not be a binary thing, it should return the index of the item if found, or the index where the item would have to go if one wants it to be inserted. Of course in CL, there are multiple return values, so it easy and convenient to do that.
17:10:19
elderK
beach: I believe it was you, a few days ago, that suggested reading docstrings from files?
17:11:02
elderK
I was wondering about that. Would you like, read-string or whatever at read time? (:documentation #.(read-doc-r-something)) ?
17:12:42
elderK
beach: Any chance you can link me to an example of like, the approach you recommend?
17:13:15
elderK
I imagine the project has a file somewhere that contains mappings of symbol -> documentation, and some other file that processes that and attaches the documentation to those symbols?
17:13:57
elderK
I've been kind of unsure how to best document my stuff, you see. So, seeing "good examples" would be really useful.
17:14:21
beach
https://github.com/robert-strandh/SICL/blob/master/Code/Sequences/Common/docstrings-en.lisp
17:15:05
beach
elderK: It would be the Common Lisp compiler and ASDF that process those. Nothing special here.
17:17:13
jcowan
beach: I understand placing the CL: docstrings outside, but do you extend this to all function-likes?
17:17:13
beach
Notice how you can have very complete documentation strings without polluting the source code with irrelevant information.
17:17:35
elderK
beach: I particularly like that aspect of this. Are those parameters only defined in the doc lisp?
17:19:31
jcowan
Okay, but what's the logic for making them external? What encouragement is there to keep them up to date as things change? (The CL spec doesn't change, that's why I see it as a special case.) I can barely keep comments *with* the code up to date.
17:20:21
elderK
jcowan: I guess it's no different than having say, "Doxygen docs" separate from C code. You have to maintain them yourself.
17:20:49
beach
jcowan: Documentation strings are for the protocol objects. Those had better not change.
17:21:19
elderK
beach: So, you don't bother documenting say, internal things? Helper functions and whatnot?
17:22:30
elderK
Like, each line starts at the same offset. Most docs I've seen are indented some on the first, and the rest are all flush.
17:23:11
jcowan
"It is not sufficient merely to prove a program correct; you have to test it too." This shows what a farce proof is.
17:23:37
jcowan
"Almost all theorems are correct, but almost all proofs have bugs." --Paul Pedersen, mathematician turned programmer
17:24:39
elderK
It just seemed like it was forwarding every to format, but always resulting in a string
17:25:30
elderK
:) for some reason, I thought docstrings were like, not evaluated. Like, that they had to be specified as strings, rather than the result of a function.
17:25:30
beach
This https://github.com/robert-strandh/SICL/blob/master/Code/CLOS/compute-discriminating-function-support.lisp is how it looks when it is meant for the maintainer.
17:26:54
jcowan
Yes, if you only use docstrings for externally visible things, I understand your reasoning. But the fact is that protocols, unless dictated by standards or arms-length relationships, change all the time too. When $EMPLOYER announces a public API this year or next, it'll have to be carefully stabilized and versioned, but the various internal APIs will undoubtedly go on changing as $PRODUCT grows new features.
17:27:26
elderK
Those *...* parameters are /defining/ the docstrings. Nto being documented themselves.
17:28:39
beach
jcowan: I am also surprised to see that, because APIs are not stable, that implies that every internal function must have a docstring.
17:29:06
elderK
~_~ Then again, most APIs I've had the misfortunate of working with in some way, have been horribly designed. Almost schizophrenic.
17:29:31
elderK
Like, professionally. I like to think of the APIs of my own personal things are much nicer :) But you know, YMMV.
17:30:12
jackdaniel
i.e some think about docstrings as a short contextual information serving a purpose of a reminder
17:30:27
beach
Either way, *I* don't plan to break my protocols, so *I* don't see the problem with detached documentation strings. If you plan on breaking your protocols, sure, put short docstrings in the code.
17:32:30
elderK
jackdaniel: I guess having that as a docstring, rather than say, a comment, is more useful since you could find that stuff in apropos or something?
17:33:35
jackdaniel
that may be how people think, yes. I don't have strong opinions about the topic except that cl's documentation abstraction is not well suited for writing software documentation
17:33:42
_death
it's also possible for something to change in a non-breaking way, and the documentation still has to be updated.. I like to see a docstring when I go to a definition
17:34:19
elderK
_death: Is there somewhere I can like, refer to, to learn about how... well, to ensure that the docstring appears properly aligned when viewed?
17:34:52
elderK
I like to have my text all indented to the same level, for... personal reasons, I guess. But I'm not sure how this would appear when someone calls documentation, or say, hovers over it in SLIME
17:37:54
jcowan
Doing such things is inevitable in an environment where not everything can be planned, much less implemented, ahead of time, and actual customers have put their money where their mouth is and have a right to expect something rather than being told "Wait a few years and you can have it perfect." They need it now, not perfect, with a believable promise of improvement.
17:38:01
_death
elderK: the thing is that docstrings appear differently in different contexts.. for example they may appear one way if you use the DOCUMENTATION function to retrieve them, and another way if you stumble upon them in the source.. personally I think a good format is a short paragraph or a line describing the function, perhaps followed by more paragraphs detailing things.. Emacs's Lisp code has lots of nice docstrings and makes for good
17:38:18
jcowan
(This is about design, not implementation; of course that is always going to have bugs.)
17:41:22
elderK
I was wondering if there was some convention I could follow wrt say, writing the documentation or directives, that would ensure it would be properly... uh, rendered, in the right places.
17:41:35
_death
elderK: since this makes the first paragraph "special", it's easier to live with the different indentation
17:42:05
elderK
_death: Right, so that explains the usual indent of the first line, then the rest flush.
17:42:34
elderK
Still, I've studied code that has say, 16+ lines in a docstring, sometimes more. It gets in the way.
17:42:53
elderK
although I imagine that might be a limitation of slimv - maybe emacs folds the documentation so it isn't so intrusive when viewing code.
17:43:17
_death
elderK: https://www.gnu.org/software/emacs/manual/html_node/elisp/Documentation-Tips.html#Documentation-Tips many of those apply to CL docstrings as well
17:44:40
jcowan
Well, understanding short-form DMC was easy, but long-form (aka RUN) DMC is another matter.
17:47:31
pjb
I'm not against storing the docstrings in a separate file. As long as you have an emacs command to display it automatically near the function you're editing, and to let you edit it along easily.
17:48:18
pjb
As much as I wouldn't be against an emacs mode that would choose itself where to store toplevel forms, without you having to C-x C-f a specific file.
17:49:33
elderK
beach: I'm having trouble finding information for ~@. Everything I can find is like, ~@ followed by some suffix.
17:50:23
makomo
elderK: find the CLHS format function and then take a look at all of the various format specifiers or w/e they're called
17:54:47
pjb
elderK: : and @ are optional flags for ~ specifiers. They are not specifiers themselves.
17:56:50
elderK
jibanes: I figure that depends on whether your implementation supports Unicode source.
17:57:04
pjb
(map 'list 'char-code "¯1↑1 2 3 4 5") #| --> (175 49 8593 49 32 50 32 51 32 52 32 53) |#
18:02:51
pjb
A lot of bugs or problems that occur in other languages, (and that let people get real actual PhD and to build whole cottage industries earning hundreds of millions each year) just cannot happen in lisp. This is why we're poor and with so few research grants.
18:04:26
jcowan
The existence of bignums in Lisp is irrelevant, because binary search happens within an array, and the array size limit is always a fixnum.
18:06:12
pjb
jcowan: depends on whether (<= (* 2 array-total-size-limit) most-positive-fixnum) or not.
18:07:21
jcowan
No, because bignum arithmetic (no overflow) plus array bounds checking will give you an error instead of the wrong answer.
18:08:07
pjb
The problem is that with modular arithmetic, of when no overflow is detected, they get the wrong index.
20:00:41
aeth
elderK, beach: If you need to work with types instead of classes, use https://github.com/markcox80/specialization-store/
20:04:04
aeth
And I think it is slower, except when inline, which can only happen when the type is declared (since CLtL2 doesn't expose the type inference, only the type declarations)
20:57:29
aeth
Working with types probably means numbers or arrays, e.g. (simple-array single-float (3)) or (integer 0 42)