libera/#commonlisp - IRC Chatlog
Search
6:56:41
splittist
There's a lot to like about Dylan. It's an interesting (...) mix of well-thought-through and rushed.
8:05:29
Tallund
Hi, I'd recently tried to implement type generics in custom collections defined by defstruct via macro. The struct would be created with a read only slot of type 'symbol' to act as a type specifier that would be read out at macro expansion time into a backquoted declaration form preceding collection operations. And I did succeed, actually- for
8:05:29
Tallund
values known at compile time. It fails as soon as I call the function-like-macro on a collection bound to a fresh let form within the REPL. I think I've read something about runtime type declarations somewhere and started trying to figure that out with a type specifier symbol retrieved only then but I've been having trouble finding anything about
8:05:30
Tallund
the evaluation semantics for the different declaration forms. Am I wasting my time here? Is there a better way to do this? Is there maybe some quicklisp package that implements generics I didn't find in the curated list?
8:09:21
flip214
I seem to remember that clouseau (or was it something in McClim?) would show a graphic of a CLOS class hierarchy, but I can't find that any more. Any hints, please? Thanks a lot!
8:10:43
beach
flip214: The CLIM listener can do that. I believe it has a "," command for that, like ,show class subclasses or something similar.
8:12:31
beach
Tallund: But it is hard to say what is going wrong since you are not showing your code.
8:13:33
Tallund
I'm a bit embarrassed to share it but I'll do so in a moment after testing it again.
8:13:34
beach
Tallund: I don't know what that means, but I was telling you about "the evaluation semantics for the different declaration forms".
8:16:51
beach
Tallund: But maybe you are asking about the semantics about type declarations in general. The answer is that the implementation is free to ignore them.
8:17:34
Tallund
I had Java's varying List<>s in mind when I said that, which could be specified to be of type 'List<String>' for example, and Java would then do its' typical compile time type checking upon insertion of elements into the specific list object and the retrieval of elements from the same object
8:17:35
beach
Tallund: The standard says that a type declaration is a promise from the programmer, and the implementation may or may not check it.
8:19:27
Tallund
That List<> bit I mentioned would be an example of collection type generics, at least as far as I know
8:19:49
beach
Tallund: Trying to make Common Lisp behave like a statically typed programming language is usually a bad idea in the first place. For example, there is no Common Lisp declaration that will declare the type of every element of a list.
8:22:09
Tallund
My thought was just to automatically generate the declarations from a type specifier given in one place, specified as a struct's slot value, instead of having to repeat the everywhere manually
8:23:55
jackdaniel
as a side note, in clim a presentation type sequence may have the element type specified
8:29:04
beach
Tallund: If you want to make sure the implementation checks your types, you need to use CHECK-TYPE or something similar. A type declaration is not guaranteed to work.
8:30:35
Tallund
I was mostly looking to leverage SBCL's type inference as far as I could get it to for producing macro expansion time declarations
8:31:39
Tallund
Type inference is the wrong term here, since I'm trying to fetch a value, it would be a sort of value inference
8:39:42
beach
Since declarations are not forms, you can't turn an element of a vector into the type supplied to a type declaration, unless that vector is known at compile time.
8:41:06
beach
And, again, even if you could, the implementation would not be guaranteed to check the type. For SBCL, I think it depends on the OPTIMIZE settings whether it does that or not.
8:42:18
Tallund
Ok, ok, ok, I think I'd need straight up reflection and macros all over the damn place in order to achieve the kind of value inference I had in mind.
8:44:07
beach
But you can store the type specifier in an element of a vector and then use TYPEP at run time.
8:44:14
Tallund
No, but I think I can manually implement some value inference via compile time form evaluation in macros.
8:45:43
Tallund
The ugliest solution I have in mind is just putting a bunch of symbols to act as type specifiers into a hash map and then I fetch the correct type specifier where it is needed
8:49:16
beach
Tallund: What is the advantage of having a symbol act as a type specifier, rather than using the type specifier itself?
8:49:47
_death
like (define-typed-stack single-float-stack single-float) that can generate the constructors and operators
8:51:11
Tallund
I think it'd be more than that, but I don't have enough intuition or knowledge to contest that statement
8:52:02
Tallund
beach: From my understanding and experimentation, type specifiers are a subset of symbols that themselves name a type, and not in the sense that symbols acting as variable names do
8:52:04
_death
(the checks may or may not be there; in sbcl, you may get some of them by its type inference, supposing the push operation is inlined)
8:53:07
Tallund
t, the symbol that is treated as the boolean value of true, also names the type T, as in, the object hiearchy root
8:55:48
Tallund
> What is the advantage of having a symbol act as a type specifier, rather than using the type specifier itself?
8:55:49
Tallund
I think I was hoping for SBCL to spit out optimized code via some kind of dynamic just in time compilation+ optimization, and with type checks
8:57:06
Tallund
Really, you should've figured out I don't know where the hell God put me once I started asking about 'evaluating declaration forms at runtime with type specifiers retrieved at runtime'
8:58:57
beach
Well, I kind of did, in that I pointed out that declarations are not forms, so they are not evaluated.
9:03:30
_death
note that compilation may be expensive, so you need to consider the tradeoff and proably make good use of caches
9:10:31
Tallund
I agree. As much as it bothers me, it would make the most sense I think if I then packaged the jit'd functions for the struct, in the struct, as a primitive pseudo object
9:13:22
flip214
set-pprint-dispatch says it's using EQUAL for type comparison -- so I can't use a base class and a generic function, I'd have to register each subclass as well.
9:14:06
flip214
Is there another mechanism that makes this easier? (Yeah, I can loop over the subclasses known at compile time, but still...)
9:14:50
_death
I think you can.. the paragraph is about determining whether there's an existing entry associated with it
9:26:03
scymtym
flip214: when you inspect a class in clouseau, expanding the sub- and superclasses "places" should display graphs. the context menu on those values can be used to toggle between list and graph display
9:32:45
pjb
Tallund: there are three ways to do it: (EVAL lambda-expression) (COERCE lambda-expression 'function) and (COMPILE nil lambda-expression)
9:33:49
pjb
Tallund: EVAL could produce an interpreted function, COMPILE must produce a compiled-function, COERCE could do what's best (fastest?) for the implementation. You also have to take into account the number of times you need to produce a function, vs. the number of times you will call it.
10:24:43
flip214
scymtym: ah yeah, right! clim has a left-to-right layout which works better with the class names, though -- top-to-bottom becomes too wide.
10:35:43
flip214
If my package names use "/" in their names ("foo/data", "foo/impl", ...), how would I escape that in a FORMAT call? (format nil "~/foo/data:my-format/" x) doesn't work, neither does \\/ ...
10:37:54
yitzi
flip214: forward slash isn't a character that needs escaping. `~/` is a format specifier that calls a function. http://clhs.lisp.se/Body/22_ced.htm
10:40:03
flip214
yitzi: my function needs a package (else CL-USER is used!), and my package name contains a #\/. But a / means "end of function name"...
10:43:17
yitzi
You can't do that. The spec says the function name can't have / in it. http://clhs.lisp.se/Body/22_ced.htm
11:39:37
scymtym
flip214: i think that depends, a horizontal layout would roughly be class-name-width * graph-depth wide while a vertical layout should be something like class-name-width * max-node-degree. so a horizontal layout would be good for a shallow hierarchy with lots of mixins or superclasses in general
11:40:30
dbotton
is there a "good" way to add to .asd files the ability to do a git clone (and when needed a git pull)?
11:41:38
flip214
dbotton: https://asdf.common-lisp.dev/asdf/Creating-new-operations.html add a :git-pull operation?
12:05:01
dim
I'd say thanks to Quicklisp it's not needed that much; in between releases I would simply git clone/pull into quicklisp/local-projects though
12:43:52
pjb
flip214: (defpackage "FMT" (:use) (:import-from "FOO/DATA" "MY-FORMAT") (:export "MY-FORMAT")) (format t "~/fmt:my-format/" arg)
12:44:52
pjb
flip214: and if your function itself has a bad name: (defun fmt:my-format (&rest args) (apply #'foo/data:my/bad/name args))
16:51:58
dbotton
Is there a way to check if a directory exists without creating it? (only found ensure-directories-exist)