Fork me on GitHub

Crud; can I change the title of my issue on the clojure issue tracker? I messed up:


@lvh you should see an “Edit” button button on the top left corner


it may be the case that you don’t have the necessary permissions, which you need to request to an admin


Oh it seems you already knew that, reading your comment


happy to change it for you


I don’t know if that means I don’t have the permissions or I’m just going blind and can’t find the button you’re talking about 🙂


the title should end just before the comma


@hiredman definterface still follows the old version of type hinting (ie. on the symbol). Is that intentional?


Hi @yogthos wanted to say thank you for clj-pdf. So great that there’s an easy library for generating PDF’s available.


@sandbags: thanks, glad to hear it's useful 😉


very much so, the hiccup like approach is especially welcome


that it actually just seems to work is also cool, last time i tried generating PDF’s (a few years ago it has to be said) it seemed like a nightmare


yeah that was the main motivation


i ended up generating HTML and automating print-to-PDF


which wasn’t ideal


I had to do a lot of report generation, and found all the libs available at the time were just painful to use


can someone help me understand what's "special" about Lisp REPLs? how is it different than ruby's irb or python's repl?


I think it's not that special 🙂 Clojurians prefer their time with REPL-connected editors instead


so when you spin up a luminus server w lein run


something interesting is that Clojure code is often short and well-encapsulated, so calling doc and source against a symbol (function, macro...) is helpful


it starts a repl server as well. is the idea here that the repl server lets a connected repl live-inspect objects/running code on the web server?


i guess, why is it significant that spinning up the web server also spins up a repl server? why couldn't i just spin it up separate?


Connectivity of your editor to the REPL is one one of the most undersold aspects of Clojure. During development you can modify your running server on the fly or inspect data flowing through your system.


i'm not sure if the ability to control running app from repl is special. I don't know if Python and Ruby support it well


the reason to start both is just about economics: start up time 🙂


wait, it isn't. You should start them from the same shell prompt so the repl can control the web server later


We run a REPL server inside all our long-running processes - even in production. That way we can attach to a running process and inspect it, and apply live patches if necessary (which we do from time to time).


When developing, we try to run as much as possible of the application in the REPL (using Stuart Sierra's Component these days) so we can live edit as we're developing.


Do the Python / Ruby REPL support that sort of workflow?


Being a lisp makes it very suitable for sending code from an editor to a REPL, because it's airways clear what the form before /after the cursor is. In other languages that's ambiguous. So e.g. There's inf-ruby for emacs, and it's pretty cool, but not as easy to work with as inferior-lisp


that said it's also just cultural. Some languages like to have automatic test runners as the main feedback loop, for lisps it tends to be more repl driven

Alex Miller (Clojure team)18:08:17

@moxaj definterface puts it in a different place to echo Java placement - that's intentional


can you instantiate a record if its passed as an argument? e.g. (let [foo Foo] (foo. 123)) (Foo is a (defrecord Foo [x]))


@plexus: what do you mean about the clear airways?


sorry that was autocorrect, I meant "it's always clear"


@plexus what do you mean the cursor? do you mean syntactically you always know when the "whole" lisp command is complete and ready to be sent because parentheses make it clear vs newlines/indentation?


I mean if you're in a position in a buffer in Emacs and press C-x C-e, it will evaluate the form before "point" (the cursor position). Because it's s-expressions this is well defined and easy to parse. For other languages it's much harder to figure out where the expression starts and ends, and it may even be up for debate


x = foo && bar("baz")| with | indicating the cursor position. Do I want to evaluate bar("baz"), foo && bar("baz") or x = foo & bar("baz")? there's no way to tell, you can agree on one interpretation, but the user no longer has a choice


(def x (and foo (bar "baz")))| now by moving my cursor I can show exactly which expression I'm interested in


so usually when sending "commands"/expressions to the server repl, you usually send a snippet by pointing the cursor to inside an s-expr and only that s-expr gets sent for eval


yeah that's a very common way of doing it, and if it's all plain values and pure functions then you can evaluate the inside forms, see what their results are, then move inside out and really get an understanding of what data is going through your system


it's a great way to poke at things when they aren't working as expected, "is this getting the inputs I'm expecting?" "is it generating the output I'm expecting?", "how about the next thing?"


but if you grab a s-expr that includes symbols external to the portion you selected (which seems like a very common thing), how do you supply those values for the repl?


yeah that is of-course common, I would just copy the form I'm interested in (again easy because of s-expressions) and fill in the gaps with hardcoded values, either directly, or by wrapping it in a let


cool. thank you!


@seancorfield I come from a rails-y background, and most of the servers i spin up use forking / threading to spin up multiple instances of the same server; if your prod servers spin up a repl, do you just avoid the forking (come to think of it i don't think you can fork in java), or is there any complications live-patching a multithreaded server?


in the Ruby/Rails world the multiprocess model is very common because Ruby's lack of native threads plus the GVL (global vm lock) mean it can only really occupy a single core at a time. Java has native threads, and web-servers will use threads and thread pools to handle requests, so a single JVM can utilize the full CPU


when you connect to a repl inside that process and redefine a function then all threads will pick that up


so that's what a live patch is. just providing a new series of defs / defns


and the immutable nature makes that a reasonable safe/feasible thing to do relative to other languages


yeah, basically. It's pretty cool, you can figure out a bug and have it fixed in production in seconds. The time it takes to set up an SSH tunnel and do M-x cider-connect


of course usual warnings of messing with production apply, but on the other hand you can revert to the old definition just as quickly


can also be handy for quickly running some ad-hoc queries


@plexus btw i believe ruby has native threads even though it used to only be green threads


since 1.9 i think


i'd be curious to hear the in-depth technical details as to how Clojure supports live patching whereas w Ruby/Rails i believe you run into issues of class caching if you tried something like that


you're right about the threads, but the GVL still prevents them from actually running in parallel


try this in irb, require 'securerandom'; 4.times { { loop { SecureRandom.base64(100) }}}, then have a look at htop, you should see 4 cores at close to 100%, but you don't


rubinius gets rid of GIL though i think


but confirm on mri


alexmiller: Thanks for the edit permission!


@machty: if you’re interested to see how the REPL driven workflow works in Clojure, I live coded a small Luminus app in a talk I gave recently


Has anyone used Lambada? I have an executable (ffmpeg) and I used the lein app template with lambada to compile a stand alone jar. I added the executable alongside the uberjar in the root of the zip file. When I run it, though, the name of the function is not found.