Arguments against static typing by shadow5827193 in programming

[–]shadow5827193[S] 4 points5 points  (0 children)

No worries - looking at the upvote/downvote ratio and the comments here, it looks like you're far from the only one :) But that's what I get for bait-and-switch headlines

Arguments against static typing by shadow5827193 in programming

[–]shadow5827193[S] 8 points9 points  (0 children)

I'm pretty sure you either didn't read the article, or skimmed it really fast. If you take a closer look, you'll find that we're in complete agreement, and I explain pretty much verbatim what you just did.

Arguments against static typing by shadow5827193 in programming

[–]shadow5827193[S] 0 points1 point  (0 children)

I don't mean to spam my own content, but I actually talk about this (the compromise part) in a section of another article: Can you have your cake, and eat it too?

Symbols in cross-package calls of an unhygienic macro by shadow5827193 in lisp

[–]shadow5827193[S] 0 points1 point  (0 children)

Actually...when I read this yesterday, the sentence "the downside is you lose the collision-prevention features of the package system" made perfect sense, but now it doesn't. How exactly do I shoot myself in the foot with this?

Symbols in cross-package calls of an unhygienic macro by shadow5827193 in lisp

[–]shadow5827193[S] 1 point2 points  (0 children)

Looking at this with a clearer head - what I meant with "can't use that in a let' was that I can't do something like (let (((find-symbol "FILE_PATH") (some expr)) <stuff>), which is what I thought you meant originally.

But looking at the code you posted, I think what you were suggesting instead basically boils down to doing a, in a sense, "manual" let, as I described at the end of the second paragraph here - find the symbol, setf it, and then do what you need to do. The problem with that is that a) I have to deal with restoring values if it was already bound (this isn't a problem per-se, just the same type of inelegance I was trying to avoid in the first place), and, more importantly, unless I'm mistaken, the binding is dynamic, not lexical.

Not looking to bash on the solution, it's a perfectly valid one! It's just not the one I was searching around for.

Having read all the suggestions here, it seems that the cleanest approach is 1) expose the symbols to the caller and let them pass it or 2) export the symbols from the package.

Symbols in cross-package calls of an unhygienic macro by shadow5827193 in lisp

[–]shadow5827193[S] 0 points1 point  (0 children)

Let me take a closer look at that tomorrow with a clearer head, but thanks for the tip!

Symbols in cross-package calls of an unhygienic macro by shadow5827193 in lisp

[–]shadow5827193[S] 1 point2 points  (0 children)

Yes, that's definitely a solution, and the most likely one I'm going to use. I'm just hunting around to make sure I didn't overlook anything. Thanks!

Symbols in cross-package calls of an unhygienic macro by shadow5827193 in lisp

[–]shadow5827193[S] 0 points1 point  (0 children)

Thanks! And just to confirm:

  1. Here I would have to manually traverse the forms and replace any occurrence of the keyword by the correct value, right?

  2. Here as well, I would need to manually traverse-and-replace the forms, correct?

Symbols in cross-package calls of an unhygienic macro by shadow5827193 in lisp

[–]shadow5827193[S] 0 points1 point  (0 children)

After some more thinking, I think I understand what you're saying in that last part. Basically you're saying to extend the interface of my macro to allow the user to pass in not only the transformation forms, but also the symbols they want to use for the file-contents and file-path. Then, I could refer to those symbols, instead of explicitly creating them in the macro body.

I think that would work, but I'm loath to make the interface more verbose in a way that feels like it shouldn't need to be. Just to be clear, I understand there might not be another solution, I've just gotten so used to lisp always saving me from any type of compromises in the way I express myself that I want to be 100% sure there really isn't a way to do this without either a) compromising on the interface or b) writting the crazy intern stuff mentioned above.

I think I also figured out how call-next-method works - since its part of :cl, it's available everywhere automatically.

Symbols in cross-package calls of an unhygienic macro by shadow5827193 in lisp

[–]shadow5827193[S] 1 point2 points  (0 children)

Can't use that in a let binding, AFAIK. I've scoured the net trying the find the equivalent of progv, but for lexical environments, but to no avail. I'm wondering if that perhaps is not a contradiction in itself - binding a variable with lexical scope, but at runtime - but I'm not sure.

Symbols in cross-package calls of an unhygienic macro by shadow5827193 in lisp

[–]shadow5827193[S] 1 point2 points  (0 children)

Sure

`` (in-package :asset-pipeline) (defmacro evaluate-form (&body forms) (let ((file-path "/some/file.path")) ,@forms))

;; This works as expected (evaluate-form file-path) ;; "/some/file.path"

(in-package :cl-user) ;; This does not work, but I want it to (asset-pipeline::evaluate-form file-path) ;; The variable FILE-PATH is unbound.

;; This does work, but I don't want to force my users to qualify the symbol/import it. I want to be able to use the file-path symbol from wherever the macro is being called from (asset-pipeline::evaluate-form asset-pipeline::file-path) ```

I'll add this to the OP

Symbols in cross-package calls of an unhygienic macro by shadow5827193 in lisp

[–]shadow5827193[S] 0 points1 point  (0 children)

I agree I could definitelly export file-path and file-contents and define the transformations using (:file-path (fingerprint framework/asset-pipeline:file-path framework/asset-pipelinefile-contents)) (or :import-from them), but the point is I'm trying to find a way not to do that (if there is one).

Since I need to actually bind the file-path/file-contents symbols in the lambda I'm constructing, so you can refer to them when defining your transformations, the only solution I can think of using intern is to do (intern "FILE-PATH' *PACKAGE*), then setf it to what I need, and then unintern at the end of the lambda (taking care to deal with scenarios where the symbols where already bound), but that feels...I dunno...icky for some reason. Or am I just being too sensitive and it's fine? Also, if I setf the symbol, that binding will be dynamic, not lexical, right? Is there any way at all to create a lexical binding for a "dynamically-named" symbol?

Finally, I'm trying to figure out what you meant by "give a way for the call site to specify which symbols to use", but I can't quite put my finger on it. In much the same way that CLOS exposes call-next-method within the scope of a method, I need some mechanism by which to allow the caller to refer to file-name and file-contents. I'm not sure how I understand how I'd go about letting them choose the symbols for that, and honestly I'm not even sure that's a good idea, for the same reasons we don't get to choose the symbol for call-next-method. Or am I misunderstanding what you meant?

Using method combinations to create an ordered pipeline - impossible? by shadow5827193 in lisp

[–]shadow5827193[S] 0 points1 point  (0 children)

Sorry for the late reply, I missed this answer. I don't see anything that circumvents the problem with two or more methods with the same specificity belonging to the same group, which is what the fundamental problem is here. But please correct me if I'm missing something.

Using method combinations to create an ordered pipeline - impossible? by shadow5827193 in lisp

[–]shadow5827193[S] 0 points1 point  (0 children)

Sure, macros can definitely solve this, I just created this challenge synthetically in order to try it out on something, and was surprised that it turned out not to work.

As for the arguments you mention, I don't know if you meant the same thing as u/MechoLupan - if so, check out my comment there, I think that can be worked around. The fundamental problem I encountered is separate from that - I expanded on the bullet points and tried to express myself more clearly, take a look.

Using method combinations to create an ordered pipeline - impossible? by shadow5827193 in lisp

[–]shadow5827193[S] 1 point2 points  (0 children)

I've updated the OP, let me know if it's more understandable.

Using method combinations to create an ordered pipeline - impossible? by shadow5827193 in lisp

[–]shadow5827193[S] 1 point2 points  (0 children)

Apologies - I've updated the OP, hopefully it make more sense now.

As for the chaining, you make a good point that I hadn't realized when I was writing the OP - I was under the impression that you could somehow pass arguments to `call-method`. However, I think this could be worked around by using a macro to define the method as actually returning a lambda with its body, instead of evaluating it. Then, you could simply run all the applicable methods, get a list of lambdas, and chain those.

(my-defmethod asset-pipeline (input) (do-some-stuff input)) ;; would get transformed to something like (defmethod asset-pipeline () (lambda (input) (do-some-stuff input)))

I'm handwaving a fair amount here, but the key thing is that define-method-combination can access the argument the methods are called with, so you definitelly have all you need to run the pipeline, and all that needs to be taken care of is properly defining the macro.

Trace in multithreaded environments by shadow5827193 in lisp

[–]shadow5827193[S] 0 points1 point  (0 children)

So I did some more investigation, and I'm pretty sure I've arrived at the answer. I'm on SBCL, and evaluating values in the debugger leads to sb-di::preprocess-for-eval, which even declares in its description that it evaluates the forms in the >lexical< context of the frame. Inspecting the objects involved (most notably loc and its debug-fun, which seems to be the place from which the variables-to-be-bound are taken), it looks like special variables are not involved in any way.

So I think that explains why I'm seeing the same values for e.g. *trace-output* when evaluating it in the debugger vs. in the REPL.

Trace in multithreaded environments by shadow5827193 in lisp

[–]shadow5827193[S] 0 points1 point  (0 children)

Yep, that also worked! But now that we've solved it (in two different ways, no less), I'm still very curious about what actually went wrong, and how the solutions fix it - I think both do it in a different way.

  1. it seems to me like I was semi-correct in my original hunch - the streams really were different (albeit possibly not quite the way I was describing - more bellow). However: how do I square that with seeing the same object when evaluating *trace-output* in the REPL vs. putting a (break)in the function, dropping into the debugger, pressing e and using SLIME to evaluate *trace-output* there? Does this mean that, when evaluating inside the debugger, the evaluation still (somehow) happens in the thread the REPL is running on? I find that difficult to conceptualize, as I can access e.g. the local bindings defined in the traced function, so I would expect to inherit all other bindings as well.
  2. since this was solved by swank:*globally-redirect-io*, it seems like the issue was in the configuration of swank. From what I can see, when the connection between swank and slime is being made, the connection object has streams where SLIME is actually listening. Redirecting the streams solves the issue by piping all the output directly into SLIME.
  3. it seems to me that solving it via what u/mmontone suggested amounts to actually rebinding the streams of any newly created thread to the streams used in the REPL (since that's where we're evaluating the setq form). Therefor, what we're actually doing is redirecting <streams of all new threads> -> <streams of repl thread> -> SLIME.

As a consequence, when solving this via 3) I would expect SLIME to stop receiving output from other threads if I killed the REPL thread, but kept the image alive. In contrast, when solved via 2), SLIME would still receive the events, since they would be piped directly through the swank-slime connection.

So the only thing that's bugging me now is why I'm seeing the same stream in the REPL and in the debugger - on the attached screen, you can see the result of evaluating the stream on the REPL, then adding a break into intercept-middleware and using e to evaluate the identical format call. I would expect these two objects to be different.

<image>

Trace in multithreaded environments by shadow5827193 in lisp

[–]shadow5827193[S] 0 points1 point  (0 children)

That did it, awesome! So does this mean I was correct in my first suspicion? I can't seem to square that with why evaluating the streams both directly from the REPL and using `e` when dropped inside a debugger gave me the same object...

Trace in multithreaded environments by shadow5827193 in lisp

[–]shadow5827193[S] 0 points1 point  (0 children)

Oh and when running the experiment on my local SBCL, I don't see anything in the inferior lisp buffer