Hacker Newsnew | past | comments | ask | show | jobs | submit | graphene's commentslogin

on that note, are you aware that the globe on stripe.com is rotating in the wrong direction?


This is a tricky one. The majority of worldwide software revenue comes from companies in the North Hemisphere who read left-to-right, so most globes are oriented this way.


Can't tell if sarcasm...? What I mean is that the globe should rotate towards the East, not towards the West. This is of course assuming a stationary camera!


Yes and the reply was saying that to the majority of readers (who read left to right), the globe spinning as it does, probably feels more subconsciously comfortable to our minds.

It's an artistic interpretation of a globe. It's not meant to be a scientifically accurate representation (one could say that the oceans aren't grey either, or that countries aren't sets of dots, or that the Earth isn't a sphere but an oblong spheroid, slightly squished at the poles). Again, scientific accuracy isn't paramount here.


This is actually a very intersting tangent! If I visualize interacting with a physical globe, I'm going to spin it left, as if I was "reading" the globe left-to-right. The rotation displayed on the stripe website is not the rotation of the Earth, it's the rotation of a globe!


It's not portraying any sunlight, so just think of it as the camera rotating around the globe.


So cool to see you guys go from strength to strength since the old days in our EF cohort!

Onwards and upwards!


<3 Hope all is well with you!


From the article:

    Where does the money go?

    The penalty is divided up between the other European
    data authorities, while the money that comes to the
    ICO goes directly to the Treasury.
So it seems most of it will go to other European data authorities.


Ah thanks, I missed that. It usually all goes to HM Treasury but this is a joint operation between multiple EU supervisory authorities.

"ICO has been investigating this case as lead supervisory authority on behalf of other EU Member State data protection authorities. It has also liaised with other regulators. Under the GDPR ‘one stop shop’ provisions the data protection authorities in the EU whose residents have been affected will also have the chance to comment on the ICO’s findings."

https://ico.org.uk/about-the-ico/news-and-events/news-and-bl...


That's really cool! I checked Rigetti's github but there seem to be no open source Julia projects there (although, somewhat surprisingly, lots of Common Lisp!). Are you free to say what Julia is being used for at Rigetti (and Intel), and whether there are any plans to release things as open source in the future?


At Intel I developed a few product modeling tools in Julia, including one that's now used in the introduction of every new product. The only real annoyances that I ran into were related to dependency management in Pkg2, but I think Pkg3 should solve all of that. I'm quite new at Rigetti, but I would suggest keeping an eye on our GitHub page.


FWIW, it's exactly what I've heard when talking to Uber drivers in London. One guy used to work as a minicab driver; he prefers Uber because he can choose his hours, doesn't get cut out of lucrative jobs to the benefit of the company owner's nephew, and feels safer at night due to the rating system.


None of which is prevented by making Uber comply with the law.

The issue is that they're not treating them as contractors when it benefits Uber, but are treating them as contractors when it benefits Uber.

They need to pick on or the other. If one of those options does not work with the features Uber wants to provide, then they have to make a choice.


There will clearly be fewer driving opportunities if a minimum wage is instituted. There's an economic cost to be paid for price floors. They invariably increase the amount of supply left unutilized. If they didn't you could increase aggregate-demand/GDP simply by raising the minimum wage.


There is a substantial cost to society in subsidizing low paying companies by making it possible for people to survive well enough on these low salaries that they are willing to take these jobs too, in harming companies that innovate in other ways in favor of companies that exploit the opportunity to offer low pay.

We're incentivising companies to squeeze salaries instead of innovating. To me that is the exact opposite of what we should do. If anything, minimum wage should be pushed higher and higher at above inflation, as an incentive to invest in labor saving measures.

There's no reason why we should encourage wasting human capacity by making it easy to exploit people for low wages.

(Yes, this would mean dealing with unemployment by e.g. reducing working time and/or basic income variations or similar)


It may have been the "literally scared for our lives" part.


There's deeplearningbook.org, which starts with the basic maths and then goes into considerable detail on cutting edge work.


It assumes a math background implicitly. I feel like you need some context already to get value out of it. I wouldn't bother reading it without doing something hands on or going through another course like cs231n or fastai first. It's an excellent book regardless of the above points.


(EU national in London) Not at all. I think the doomsday threats are overblown and the negotiating parties will reach a mutually beneficial deal at the 11th hour.

Much more concerned about the possibility of the current Labour party gaining power actually.


I think the chances of a deal are about 70% and trending lower.

The only fudge that can work at the 11th hour is staying in the EU in all but name; there is no way the EU can agree to something non-disruptive quickly without risking it continuing on indefinitely, which means it needs to be almost identical to what went before. And I don't think the Tories can sell that to either the public or their own membership.

A mutually beneficial deal will never happen; the UK cannot come out of Brexit better than before. Any mutual benefit can only come after the UK has climbed out of a pit scary enough to put off any further risk of countries leaving.

If public opinion on Brexit changes, then it might be different. I don't see that happening yet though, and the risks all seem to be on the downside - painting the EU as intransigent and punishing.


> If public opinion on Brexit changes, then it might be different. I don't see that happening yet though

I think it might. Polls on the subject have been tightening, and even showing signs of moving towards halting leaving[1].

I think as more of the leave voters die off (as they were predominantly older voters), and realisations about the actual real-world consequences of leaving filter through to the public consciousness, the process may be halted, softened, or reversed.

That's mostly conjecture (and hope, honestly) on my part, though.

[1] https://twitter.com/MSmithsonPB/status/918740988365074432


Yeah, I spent most of last year having thoughts like this about Trump becoming president. He'll never get nominated.... he won't win.... yeah but surely something will happen at the 11th hour, he can't possibly become president, it's too crazy...

And now look where we are. I'm not sure your optimism is warranted. We're living in strange times.


US economy is doing pretty well under Trump, no?


No, the US stock market is doing pretty well. These are different things.


That’s not how economics works. The economy was depressed due to the election year (uncertainty) and bounced back.

Any additional growth is mostly attributable to Obamaera policy (tho some short term juicing of markets has happened under Trump occasionally).


Trump has done almost nothing to change it. It's doing well because of Obama.


We're coming up on a year of record highs. How long does one have to wait until a President is allowed to take credit?


People should describe a policy, and a means for that policy to have made a difference to the economy, when taking credit. Otherwise it's like taking credit for the sun rising.


At the very least until their first budget goes into effect. This is not a new concept. It's why the stupid right wing memes in like.. April were all "Obamas first 100 days vs Trumps first 100" - because Obama was dealing with the freaking recession and the Bush policies and budget.

Again - this is not new.


> How long does one have to wait until a President is allowed to take credit?

Depends on whether the hearer likes or dislikes him.


Economic growth is not the only reason to live in a country.


This is wishful thinking, to put it mildly. What on earth concerns you about a labour government?


Aside from tolerance for Antisemitism, being soft on Russia, picking and choosing on human rights (e.g. Syria), and appealing to base instincts on immigration (Eastern Europeans are keeping your wages down), what's so bad about Corbyn-led Labour?


Antisemitism: mainstream Labour isn't antisemitic, that was largely a point pushed in our right media to discredit them. The left wing of the party is definitely anti-Israel though, and pro-Israel forces always try to conflate the two. The Labour party is much, much less racist than the Tory party on average, it's the sort of thing that's hard to prove with a neat fact you just have to spend time in a pub with either side or read a lot of their literature for dog-whistles. soft on Russia: who knows, it's not like we have the military clout for it to matter much picking and choosing on human rights: doesn't everyone immigration racism - no, Corbyn's message (that i also disagree with actually) is to redirect the focus onto exploitative employers. It's his talking point on immigration along with NHS staffing, every time. The labour party has gotten worse on this but they're still miles behind the Tories

Sorry to do politics on HN but this post needed to be called out, none of these points are a combination of relevant and applying more to Labour than the Tories.


Don't all of those apply to conservative party as well? (Perhaps substitute Islamophobia for antisemitism)


Yes, yes they do. Except more so.


Oh I see. It's Corbyn's right-wing credentials that put you off him. Of course.


I'm neither left nor right. Corbyn manages to bring together the worst of both worlds.


It doesn't matter how left-wing a politician appears to be, or even how left-wing they are in general; if they hold an odious reactionary opinion, they can be called out on that opinion.


Taxes are concerning. More taxes on the medium-upper class.


[flagged]


The Daily Mail isn't even an acceptable source on Wikipedia let alone on HN.


Okay. But is The Guardian acceptable in your political view?

https://www.theguardian.com/commentisfree/2015/nov/19/marxis...


Meh, that is not a critique of Corbyn as a Marxist, it's using communism as a scare word without delving into what Marxism actually is and why Corbyn matches the definition. Do you have a critique by someone who actually knows what Marxism is?

I can find plenty of descriptions of many politicians as Fascist (and usually better researched than this), doesn't mean most of them are.


Specifically that article is by Damian McBride, who was Gordon Brown's SPAD. It's continuation of a political brawl by means of a newspaper column. Not a very nice chap:

"On 11 April 2009, he resigned his position after it emerged on a political blog that he and another Labour Party advisor, Derek Draper, had exchanged emails discussing the possibility of disseminating rumours McBride had fabricated about the private lives of some Conservative Party politicians and their spouses. The emails from McBride had been sent from his No. 10 Downing Street email account."



I didn't say anything about my political view. I said the Daily Mail is not acceptable as a source in Wikipedia. Which it is not.


In this case there are plenty of sources saying the same thing so it does not make sense to shoot the messenger.

https://www.startpage.com/do/search?q=corbyn+marxism


A web search doesn't count as research. No reputable journalist in the UK genuinely believes that Corbyn is a marxist.

It's lazy 'googling' about 'facts' that landed America with Trump.


A web search is not meant to count as research, it is the equivalent of a library catalogue search. You're meant to follow the links and find out what is written on the subject. It is the internet equivalent of a literature study and as such a form or research. The assumption here is that the reader is intelligent enough to be able to separate authoritative sources from hearsay and agenda-based publications.

By the way, using terms like "no reputable journalist" is called "Master suppression technique" or "domination technique" [1]. It is detrimental to having a fact-based discussion and generally seen as a cop-out for those who don't have real arguments to add to the discussion.

[1] https://en.wikipedia.org/wiki/Master_suppression_technique


> negotiating parties will reach a mutually beneficial deal at the 11th hour

Compare with the situation of Greece. There was essentially very little change in the EU position, and Greece eventually realised they had no leverage and would be worse off outside the EU and had to acquiesce.

The only deals that have a chance of happening are "forget the whole thing, no Brexit" or maybe "Norway" (EEA including free movement, but no voting rights). "No deal" would be a disaster.

And if it's left until the 11th hour plenty of companies will have no choice but to avoid planning beyond that time. Like Ryanair pointing out that they can't take bookings without knowing what legal framework will be in place: http://www.telegraph.co.uk/news/2017/07/11/ryanair-chief-mic...

Addendum: this article by Gordon Guthrie, Erlanger and former extremely minor politician, sums up the lack of choice: https://medium.com/@gordonguthrie/no-deal-wont-happen-e185f9...


The 11th hour is already at hand. Some pretty big players are ready to trigger their contingency plans if certainty about future remains unclear: https://www.theguardian.com/politics/2017/oct/04/eu-transiti...


Minor politician, ya cheeky git ;-)


I do something similar, here's my Makefile -- I have scripts that build figures in a separate directory, /figures. I'm sure it could be terser, but it does the job for me.

    texfiles = acronyms.tex analytical_mecs_procedure.tex analytical_mecs.tex \
               anderson_old.tex background.tex chaincap.tex \
               conclusions.tex cvici.tex gold_chain_test.tex introduction.tex \
               main.tex mcci_manual.tex methods.tex moljunc.tex \
               tb_sum_test.tex times_procedure.tex tm_mcci_workflow.tex tmo.tex \
               vici_intro.tex
 
    # dynamically generated figures
 
 
    all: main.pdf
 
    main.pdf: $(texfiles) figures/junction_occupations.pdf figures/overlaps_barplot.pdf \
                          figures/transmission_comparison.pdf \
                          figures/wigner_distributions.pdf
        pdflatex main.tex && bibtex main && pdflatex main.tex && pdflatex main.tex
 
    figures/junction_occupations.pdf: figures/junction_occupations.hs
        ghc --make figures/junction_occupations.hs
        figures/junction_occupations -w 800 -h 400 -o figures/junction_occupations.svg
        inkscape -D -A figures/junction_occupations.pdf figures/junction_occupations.svg 
 
    figures/overlaps_barplot.pdf: figures/overlaps_barplot.py
        python figures/overlaps_barplot.py
 
    figures/transmission_comparison.pdf: figures/transmission_comparison.py
        python figures/transmission_comparison.py
 
    figures/wigner_distributions.pdf: figures/wigner_distributions.py
        python figures/transmission_comparison.py
 
    clean:
        rm *.log *.aux *.blg *.bbl *.dvi main.pdf


I noticed that you have some file dependencies not encoded in the targets. Also, you might like reading up on Automatic Variables ($@, $^, $<, etc). Anyway, just for fun I tried rewriting your script in a way that should Just Work a little better.

    texfiles    = $(wildcard *.tex)

    figures_ink = figures/junction_occupations.pdf
    figures_py  = figures/overlaps_barplot.pdf        \
                  figures/transmission_comparison.pdf \
                  figures/wigner_distributions.pdf
    figures     = $(figures_ink) $(figures_py)


    main.pdf: main.tex $(texfiles) $(figures)
        pdflatex $<
        bibtex $(<:*.tex=*)
        pdflatex $<
        pdflatex $<

    figures/junction_occupations: %: %.hs
        ghc --make $^

    figures/junction_occupations.svg: figures/junction_occupations
        $< -w 800 -h 400 -o $@

    $(figures_ink): %.pdf: %.svg
        inkscape -D -A $@ $^

    $(figures_py): %.pdf: %.py
        python $^

    clean:
        rm *.log *.aux *.blg *.bbl *.dvi main.pdf


Check out latexmk: it keeps track of having to run bibtex etc, and runs latex "enough times" so that all equation refs etc have stabilised. (Latexmk -pdf to build a pdf, default is dvi.)


Yes, I don't think I'll get a chance to dig out my Makefile. But my Makefile was very much like this.


  figures/%.pdf: figures/%.py
      python $<


Honest question, how is this different from what you can do in e.g. python? The python interpreter supports reloading of modules and evaluation of expressions, is there functionality that CL has above and beyond this that makes it more powerful?


Can you recompile a function on a running program and have it pick up the new definition? Can you change a class at runtime, and then adjust already existing objects to match the new definition in a controlled way, without data loss? Can you forget to define a function, or initialize a variable, only to be allowed by the debugger to provide a new definition / value on the fly and continue execution?

Those are some examples off the top of my head, but the general point is that unlike mainstream languages, Lisp languages evolved into environment for interactive construction and modification on a continuously running program, which is a bit different way of working than the regular write-compile-run cycle.


Some, most?, of the things you mention are available in other languages but they generally do not come together so well and they feel clunky.

I think it's not so much whether the features exist in other languages since we all know they can be added but the whole being more than the sum of its parts.


I find Clojure to be practical today, and it supports most of those. I believe it lags a little behind CLs development features, but since it tends to force immutable and referentially transparent code, I find that helps too. Since swapping things out is trivial in those cases.


With Javascript as an example, it can indeed be used in this fashion, as I expect also Python. But the key difference is the community of CL is this is a standard way of working, and the tools are built around this.


I'm not much of a Pythonist, but I have been doing CL since before ANSI CL.

To me the thing that CL has that has yet to be matched by any other languages, REPL-based or not, static or not, is the amazing condition system and dynamic restarts for handling problems. For building and debugging systems this is an utterly amazing thing. It also allows composing exceptional conditions in a reasonable way.

Every other language I use (e.g., Clojure these days a lot) I constantly miss this amazing stack-walking ability and conditional restarts.

Every time I boot my old Symbolics computers and something happens and I get a GUI restart, I'm just amazed at what we have lost through two decades of non-CL living.


The sound of it makes me think or Erlang's OTP system. I've just been really digging into it lately. Though the stack walking seems different, the entire OTP system is wonderful in letting you deal with errors by composing restartable processes and supervisors.

Heck, it's easier to handle recovering from an error by just restarting a process and letting it follow the normal unit logic.

Do have any knowledge of how CL and Erlang/Elixir/OTP are similar or vary on error handling?


Common Lisp's restarts are not restartable processes in the Erlang sense. They are part of a facility for suspending execution of a thread of control when it encounters an error, modifying the dynamic state of the process during the suspension, and resuming execution afterward.

When an error occurs in a Common Lisp program the runtime signals a __condition__. A condition is an instance of a class that represents unexpected or otherwise exceptional situations that can arise during execution. When a condition is signaled, control searches for a registered handler that matches the type of the signaled condition. If one is found then control passes to the matching handler. If none is found then control passes to the default handler, which by default starts an interactive repl called a breakloop__.

The breakloop has access to the full dynamic state of the suspended computation, including all local and dynamic variables and all pending functions on the stack. From the breakloop a programmer can alter variable values and redefine functions and classes. For example, if you conclude that the error happened because of an incorrect function definition, you can redefine the function and tell the breakloop to resume execution as if the new definition had been called instead of the original one.

A __restart__ in this context is an option for continuing execution. Common Lisp's condition system offers the programmer the ability to choose from among available restarts in a breakloop, or to write a handler that will make the choice automatically when a condition is signaled, and it also offers the ability to define custom restarts.


I've been wanting to experiment with this. There are some libraries in Clojure that try, but it seems that the real value is the interactivity of it while developing? I haven't found the exception handlers to really add much value over normal exception handling at least in Clojure.


As an interesting example, conditions and restarts can be used to implement an interactive system that is composable with other programs. For instance, you can implement a simple y/n question handler as follows:

    (defun fn1 ()
      (if (yes-or-no-p) (print :yes) (print :no)))
    
    (defun fn2 ()
      (fn1))
[yes-or-no-p](http://clhs.lisp.se/Body/f_y_or_n.htm) is an interactive function that reads from the stdin. However, you cannot programatically answer "yes" to fn1, as other functions in the call stack (fn2) has no way to know that fn1 halts because it waits for the input from the stdin. Instead, a condition system allows this:

    (defun fn1 ()
      (restart-case (error "yes or no?")
        (yes () (print :yes))
        (no  () (print :no))))
    
    (defun fn2-interactive ()
      (fn1))

    (defun fn2-automated ()
      (hander-bind ((error (lambda (c) (invoke-restart 'yes)))) ;; handler
         (fn1)))
When you call fn2-automated, an error is signaled, handled by the handler, which invokes a restart 'yes, then :yes is printed. Interactivity is still maintained by fn2-interactive.


I'm not sure I get it. Where is the user io in the second example? I'm not sure I understand how fn2-interactive still works.


It enters the debugger due to the error. In the debugger menu you see additional entries YES and NO.

    yes or no?
       [Condition of type SIMPLE-ERROR]
    
    Restarts:
     0: [YES] YES
     1: [NO] NO
     2: [RETRY] Retry SLIME REPL evaluation request.
     3: [*ABORT] Return to SLIME's top level.
     4: [ABORT] abort thread (#<THREAD "repl-thread" RUNNING                 {1003167FA3}>)
See? All debugger menus are actually implemented as the restarts, set up at various call stacks. In this implementation of the debugger the way to select YES is to enter 0 or click it on the emacs buffer. In another debugger, it could be entering ":r 0" to the stdin. You can also implement your debugger function, which `read-line` the input stream and only recognizes a specific string, y or n, and set your function to `debugger-hook` to use it (I forgot to mention this in the above example).


Ok right. That's why I feel in Clojure it doesn't provide as much, because it doesn't hook into a debugger.

Having said that, practically, you wouldn't release a tool which has users interact at the debugger, at least for any level of more serious commercial work no?


CL's debugger is just a function, and the key is not to be distracted by the name "debugger".

As said, you can have a custom "debugger" which does not look like a debugger, but a general purpose user interface in the text terminal. For example, being "custom", it can also hide the restarts which are only meaningful for true debugging (like restart 2,3,4). (see detail [1])

It is possible for a debugger to even invoke a GUI (imagine a debugger hook which pops up a window with an OK button) or a web UI (sends a Websocket message to the client, wait for the user to click something on the browser, receive a reply and invoke the restart). In fact, SLIME is written this way: it overloads the debugger hook, and it sends and receives messages to the Emacs TCP client (thus you can click on the menu on an Emacs buffer to restart -- this action is notified back to the underlying lisp process via TCP, which then calls invoke-restart).

[1] You can obtain the list of restarts with COMPUTE-RESTARTS and filter unassociated restarts (similar to a method dispatch but is temporary / has dynamic extent -- see http://clhs.lisp.se/Body/09_adbd.htm).


I see, that's cool. Thanks for the info. So it can be used for certain form of event modeling, like a built in event system. That does sound cool.


After fooling around with porting some Common Lisp code to Python as an exercise in reinforcing my understanding of the underlying algorithms and learning Python, I would describe the difference as the Python interpreter was mostly designed with the assumption that the typical use case would be executing the interpreter with a source file as an argument [e.g. python spam.py] and not primarily as an interactive development tool that is left as a running process for days or weeks. Instead Python ships with IDLE which more reflects the idea of an interpreter running source files serially.

Or to put it another way, trace is an option that is passed to the Python interpreter. In Common Lisp (trace ...) is a function that can be called in the REPL.


The standard Python interpreter is crap. One should use IPython. I'd like to see a comparison with that one.


The standard repl for Steel Bank Common Lisp is worse than Cpython's with no basic readline support. The Common Lisp environment really shows its strengths when using a fully interactive development environment like a Lisp machine environment or Emacs with SLIME.


I'd call it the "built-in repl" rather than the standard one, since I don't think it's actually standard for people to use it directly.


CLISP has readline support.


That is exactly correct. Guido van Rossum's original paper on a scripting language called ABC which strongly influenced his later design of Python, was basically a scripting language for system administration tasks on Unix and Unix-like operating systems.


It's extremely different. You have to resort to hacks in Python to reload modules, which has unclear semantics. Python doesn't let you update function definitions while running, or let you add new polymorphic methods to dispatch on while developing. Not to mention interactive error handling isn't as powerful as Lisp's.

Python really has a glorified edit-compile-run cycle. The interpreter loop is nice for quick tests or calculations, but isn't too helpful for the incremental development of your program.


> You have to resort to hacks in Python to reload modules, which has unclear semantics.

This is the crux of the issue. Even in Python 3 the semantics for reloading modules is wrong:

Other references to the old objects (such as names external to the module) are not rebound to refer to the new objects and must be updated in each namespace where they occur if that is desired.

If a module imports objects from another module using from ... import ..., calling reload() for the other module does not redefine the objects imported from it — one way around this is to re-execute the from statement, another is to use import and qualified names (module.name) instead.

If a module instantiates instances of a class, reloading the module that defines the class does not affect the method definitions of the instances — they continue to use the old class definition. The same is true for derived classes.

https://docs.python.org/dev/library/importlib.html#importlib...

In principle Python has a runtime with type-tagged objects that you can inspect and code you can load, so it should be dynamic. Because of the way module and class loading behavior is defined you cannot actually take advantage of this dynamic runtime. Python does not really have a REPL, it has script loading akin to most Unix shells, and a second-class REPL that is useful for some limited debugging. This unnecessary dichotomy imposed on code loading makes it very different from Lisp and Smalltalk.


Common Lisp supports stopping execution of a function in the middle, redefining the function, changing the values of all accessible dynamic and lexical variables, adding new variable definitions, redefining the types of the values, and then resuming execution from the start of the redefined function, or from any other accessible control point.

It also supports writing condition handlers that can do all of the above under program control, rather than under human control. In other languages you would say "exception handlers", but Common Lisp conditions include representations of situations and responses that exceptions typically don't.

These facilities, along with things like a debugger, a tracer, support for built-in documentation, a compiler, and a disassembler, are part of the language standard, not the development environment.

Common Lisp is a language designed from the ground up for writing programs by interacting with them as they run. There aren't very many other languages like that. Smalltalk is one of them.


I've been writing in Common Lisp for 7 years and am working on a python project for ~8 month (for a machine learning task w/ Tensorflow). I am insanely irritated by countless points, to name a few:

* Python REPL does not check and warn the trivial type/arguments errors when a function is defined. It is only after the program reaches that erroneous line that an error is signaled. SBCL always warns about the function signature. Perhaps this may be customized by some global variable or a command line option, but not being warned by default is a huge waste of time, as it takes non-negligible amount of time to reach there (specifically because it is a ML task). (SBCL also warns me about type errors in most of the standard functions as well as ftype'd functions.)

* Python does not have restarts. I mean the condition system in Common Lisp. This again imposes a significant amount of slowdown on the debugging cycle as an error may be signaled only after a multi-hundreds-MB data file is loaded in the beginning of a function and then the erroneous line of code is run. In CL, when an error is signaled, the program enters the debugger and halts there, during which you can correct the program, redefine the function, then resume the code from one or two stacks above the current. In python an error always rewind the stack to the toplevel, so you have to rerun the whole function, loading that huge data file again in the middle of the stack. Don't say you are afraid of some side effects in the code, I follow "Mostly Functional Style" in CL.

* Python debugger shows the stack frame, but does not by default show the values of the arguments in the function call stack when an error is signaled. It forces you to use an ugly printf debugging style. I would like to know if it is possible to alter the way the stack is printed. In CL, a debugger is just a function stored in debugger-hook. I hope you can do something similar.

* Somehow Emacs C-M-f selects the whole line, not an expression.


With CL if you have a bug on your web server you can just connect a repl into the running server, inspect the state of the system, modify that state and update code on the fly if necessary.


I guess the key here for me would be inspecting the state of the system. I tried learning common lisp a few times and it never clicked.

When clojure came around, I tried lisping again, and for whatever reason i was ready for it, and clojure is my goto language.

That said, I'd never connect to a repl on a server and do any kind of bug fixing unless it was really dire. It's too easy to get the run state out of sync with the text source files, and I don't see why this would be different with common lisp.

I think the repl is great for development and figuring things out, but the whole idea of "program as state" seems antithetical to the ideas of functional programming. With the main issue for me being that I have to somehow keep track of this program state in my head once I start tinkering with it.

For example, say I find a function has a bug and I go into the repl on the server and fix it, in situ. Say I spot some other issues, or had them on my list of things to fix when I had time... I start modifying functions here or there. Now my "program state" no longer matches my source code, and I have to remember to fix it so that it matches. That's error prone. I could enforce my own methodology of fixing the source and copy-paste to the repl or send it in whatever way, still error prone.

I have to remember what changes I made, to what functions, and if I iterated, now I have to remember which iteration was final. Multiply that by any and all functions that are touched. It's a lot to keep track of.

So when you say "inspect the state," I have to think common lisp must have some feature for state inspection that is missing in clojure. I know there are a lot of features of common lisp, especially in stack-tracing, that clojure has no parity to. But I'm curious if common lisp has some way of completing a "round trip edit" such that an edit/correction made on a server process, in situ, are able to be easily propagated back to your master source?

If you read all that, thanks :)


> But I'm curious if common lisp has some way of completing a "round trip edit" such that an edit/correction made on a server process, in situ, are able to be easily propagated back to your master source?

In SLIME you just connect to the Lisp process, open up your versioned-controlled file, edit it, hit C-c C-c for slime-compile-defun or C-c C-k for slime-compile-and-load-file. Isn't that how CIDER works also?


True. If you are going purely functional I guess you wouldn't have much state to inspect. Plus in a stateless web server you generally want to avoid keeping state around on the server.

I remember one time, it was actually with Clojure, I had to deal with Paypal. Since paypal only sent results back to the server and not to localhost I couldn't debug the problem locally. So I connected to the server, bunged all the debug information into an atom and made a few requests. Then I could inspect the atom, make some changes and find out what the problem was and fix it right away. It took just a few minutes.

At about the same time I was also working on a C# server. There was a bug there that could only reproduce itself on the server. To fix that bug I had to put a load of logging into the source. Check the file into source control. Wait for the CI system to build and deploy. Then kick off some requests. Inspect the log files. Make some changes. Check in.. wait.. etc.. It took days to fix that bug.

Admittedly the Clojure project was mine on my own server and the C# project was on some corporate enterprise behemoth so there were other factors that hindered that project, but it did highlight to me how much quicker you can get stuff done when you have that instant feedback.

When I say inspect the state, generally I just mean inspecting the values of global variables. In CL it is possible to put breakpoints in the source and inspect all the variables up the stack. Mind you, this can be a bit hairy on the server if there are multiple people connected as there is no guarantee as to whose Slime connection will pick up the breakpoint.

The round trip edit is pretty similar to Clojure. You would generally have your source file open in Emacs, change the source code and press Ctrl+CC with the cursor in your function definition to apply your edits to the server. Then you save the file and check it in to source control. You don't have to type directly into the repl.

You don't have to work like this if you don't want to. Without mentioning any names, it has been known for the server image to be completely out of sync with the state of the source files to the point where there weren't really any source files. The work around was to just treat the server image as the master source of truth. Luckily in CL you can just dump the image to create a new executable with its current state. So for several years this one server existed only as a constantly updated binary image. I wouldn't recommend working like that, but it has been done.

Depending on your implementation - I know Clozure CL at least allows this - you can extract the source code out of the running image. So it is certainly possible to propogate back to master source. It was eventually how this one server was restored to a more orthodox source code tree..


Thanks for the reply. It seems a bit fragile and convoluted to me, but I suppose if you are used to it and are comfortable with the pitfalls it would be fine.


Yes, working directly on the server is definately fragile and fraught with all kinds of dangers. I try to avoid it as much as possible, but it is very handy having the option there as a last resort.


C# edit-and-continue sounds like a pale shadow of what's possible, and it's usually only useful locally!


If you wanted, you could have any bug in a running web server pop up a window in your editor, fix the bug within the call that's buggy, then resume execution from that point at the call stack, successfully returning results to the client. Doing so doesn't necessarily make a lot of sense, but it's a very powerful technique if you choose to use it.


This is true and awesome.

To be fair, though, I run an nREPL TCP listener on my production servers too, so I can do the same thing with Clojure. :)


Not quite. In Lisp, when you get an error, the system pauses and lets you resolve the issue before resuming the program. Sometimes this even means typing in a function really quickly before a request times out (which isn't such an insane suggestion in the context of development). In Clojure, errors like that unwind the stack and tear everything down.


Reminds me of Paul Graham's essay about how at Viaweb, they sometimes used to fix bugs (in the Lisp code) while the customers who reported them were still on the phone, and then the support staff would tell them to check whether they were sure it was a bug, by trying again - and since the bug was now fixed in the server, when they did that operation again, it would work.

I think it was in his Beating the Averages essay - the one in which he talks a lot about the advantages Lisp gave them at Viaweb, over the competition.


You could do that with a PHP site if you're working directly in production. That's not necessarily an advantage of Lisp.


I think I had not described it fully (since had read it long ago). Searched for the article just now. The Beating the Averages article [1] does not have the point I mentioned. But a more detailed article [2] linked from it, does:

[1] http://paulgraham.com/avg.html

[2] More Technical Details: http://paulgraham.com/lwba.html (note: redirects twice)

Here's the relevant section:

[ Interactive Toplevel

Lisp's interactive toplevel is a great help in developing software rapidly. But the biggest advantage for us was probably in finding bugs. As I mentioned before, with Web-based applications you have the users' data on your servers and can usually reproduce bugs.

When one of the customer support people came to me with a report of a bug in the editor, I would load the code into the Lisp interpreter and log into the user's account. If I was able to reproduce the bug I'd get an actual break loop, telling me exactly what was going wrong. Often I could fix the code and release a fix right away. And when I say right away, I mean while the user was still on the phone.

Such fast turnaround on bug fixes put us into an impossibly tempting position. If we could catch and fix a bug while the user was still on the phone, it was very tempting for us to give the user the impression that they were imagining it. And so we sometimes (to their delight) had the customer support people tell the user to just try logging in again and see if they still had the problem. And of course when the user logged back in they'd get the newly released version of the software with the bug fixed, and everything would work fine. I realize this was a bit sneaky of us, but it was also a lot of fun. ]


So it was the interactive toplevel and the break loop [1] that seem to have provided the advantage.

[1] Discussed in this same thread, e.g. this comment by mikelevins:

https://news.ycombinator.com/item?id=14677016

Not sure if PHP has that.

Incidentally, I seem to remember the following: some years ago, after playing around some with Lisp (Allegro CL from Franz, and the Lisp IDE from Lispworks, both of which supported this feature or something like it), I was trying out a then-current version of Visual Studio, and saw that it had a new feature called Edit-and-Continue, which I thought was similar to the Lisp feature.


Good point, see my other comment though.


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: