libera/#commonlisp - IRC Chatlog
Search
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)
19:12:06
nij-
Anyone knows how CFFI works? I mean, lisp has to talk to C in some way. Which channel do they use? Do they use bsd sockets?
19:14:04
Bike
cffi is not a communication between processes. it is a way for lisp code to run c code and vice versa, all in the same process.
19:14:31
Bike
lisp functions can call c functions similarly to how they would call other lisp functions, and the reverse can be done through callbacks.
19:17:37
aeth
you could always try writing a CFFI hello world and running DISASSEMBLE on the function to see what it's doing
19:18:57
pjb
or rather, use macroexpand: (macroexpand-1 '(cffi:defcfun clock :int)) #| --> (progn nil (defun clock nil (cffi-sys:%foreign-funcall "clock" (:int) :convention :cdecl :library :default))) ; t |# (macroexpand-1 ' (cffi-sys:%foreign-funcall "clock" (:int) :convention :cdecl :library :default)) #| --> (ccl:external-call "_clock" :signed-int) ; t |#
19:23:50
aeth
which is faster depends on the implementation and if it's helpful enough to comment or otherwise make known that it's calling, in this case, ccl:external-call
19:35:12
Bike
it's all running on the same machine in the end. a lisp compiler can just generate a C call instruction sequence.
19:36:33
nij-
Can I do this for other langs like python? Or does it just work for lower level langs like C?
19:39:18
aeth
the problem with other languages is that they have a much larger runtime, probably including a garbage collector, too
19:39:24
Bike
well, to run C code there probably does have to be some kind of c runtime linked in. like you're not going to be able to call into libc without linking libc.
19:40:06
Bike
C is fairly unique among programming languages in having defined binary interfaces for a variety of architectures, meaning that there is a clear and documented way to write the machine instructions to call into C
19:40:11
nij-
so for other langs, it's better to have two of them communicating via a socket or something?
19:41:08
aeth
Yes, to talk between language A and language B, you have them both pretend to talk to language C, in this case C.
19:43:04
Bike
nah, it's just that lisp and python aren't set up to talk directly, but they are both set up to talk to c. so to speak.
19:44:48
contrapunctus
nij-: pick up one of these forks - https://github.com/pinterface/burgled-batteries/network/members (unless there's something newer I don't know of...)
19:45:02
Bike
or have them in separate processes and talk over sockets. depends on what you are doing.
19:46:00
Bike
it has a runtime, but you only need to care about crt0 if you're doing pretty funky stuff
19:47:43
aeth
I was just thinking about the most overengineered to do it, which is actually probably also the most common
19:48:52
Bike
if stuff is in the same process, you might be able to send a pointer to it, so there wouldn't be any copying and it would go quick. over a socket you'd have to actually send the data. but there are other things you could do, like mmapping
19:49:35
aeth
if you don't care about the implementation and it's your highest priority, you could use a runtime that's designed for that
19:50:55
aeth
but the other language implementations might not be as fast or feature rich as their main implementations
19:51:16
nij-
Bike - about the same process could save time: different lang interprets data differently.
19:51:34
nij-
So even if they are in the same process, being able to point to the same address doesn't necessary means it's fastr right?
19:52:41
aeth
nij-: you'd probably try to meet in the middle. If something lower level than python, maybe it can have octet arrays
19:53:00
Bike
depends on the nature of the data. cffi lets you write to memory pretty much like you'd do in C, so C can read it without any kind of translation.
19:53:17
Bike
all of this stuff pretty much depends on what exactly it is you are doing. without knowing that i'm going to have to be pretty vague.
19:54:26
aeth
nij-: but there are a lot of different approaches, e.g. you could put it in a separate program, launch it with uiop:launch-program, and communicate that way (inter-process, I think).
19:54:30
nij-
I see. I want to make a lisp program that is ready to talk to any other popular languages in order to use their libraries.
19:55:04
nij-
aeth I was looking at uiop:launch-program the other day, but using :stream to talk to each other is kind of fragile.
19:55:22
nij-
For example, if both runtimes want to send others many tasks at the same time, the channel is likely to be broken.
19:55:48
nij-
So I ponder it may be safer and more robust to use a mature socket as the communication interface.
19:56:26
nij-
Bike: besides that, I expect to run intensive calculations (CPU bound) on both sides, and send large datas.
19:56:51
aeth
you should probably start with a specific solution for a specific use case or else you will just wind up with something incredibly general and overengineered, but probably not that fast in the long run... and maybe you'd reinvent microservices
19:57:39
nij-
aeth Yeah.. I'm still trying to narrow what's the best appoach to my problem. And then I will select an existing solution.
20:01:51
nij-
what do people use nowadays when it comes to communicating between run times? And what's the standard practice for common lisp?
20:03:41
White_Flame
often people create individual commands instead of having an "anything goes" rpc
20:04:02
White_Flame
with a specified command interface, then you can avoid introspection if other languages don't support it
20:04:25
aeth
these days people probably just don't care about the overhead that much and use JSON... in part because it's probably going to have to go over the network anyway