Hacker News new | past | comments | ask | show | jobs | submit login

You sir, seem to be hell-bent against REPLs :P

I agree with your point that IDEs are getting better but REPLs are getting better too, why should they be relegated to be mere artifacts of the past. Your java REPL will mostly have autocomplete, give it a chance, it really might turnout to be fun :P

And typing python in a REPL is fun for me, but fun is subjective, no point arguing about it :)




I'm not against REPLs I just think they have been around since early Lisp and there are vast improvements that can be made.

I use REPLs all the time... Bash is basically a REPL :)

The reason I think Java REPL would be awful is not because I dislike REPLs but because Java is really painful for that kind of mutable command line like development. Like just making a damn struct like object is absolutely painful and Java does not have structural types (ignoring FunctionalInterfaces which isn't really structure types).

Python REPL is painful because of required indentation and again because Python is similar to Java and prefers nominal types.

I'm not against Python or Java but I don't think the language design of those languages really works well for REPL compared to say Lisp, OCaml, Haskell, or even Scala and Smalltalk.


Fair enough, I think I am having difficulty in understanding your views because firstly I have never worked with Java, closest language I have worked with is C# and I don't particularly dislike its REPL, its nothing to write home about but I don't particularly hate it either.

Secondly the image we two have in mind of a REPL seems to be different. When I am thinking about a REPL the image I have in mind is of Jupyter Notebook and Clojure, Elixir, Idris, Haskell REPLs in Emacs. The image you have in mind seems to be a basic console, so having spent my day working in a Jupyter Notebook I sit here thinking what you mean by Python's significant whitespace being an issue(Haskell and Idris have significant whitespace too). But now I do understand your views :)

P.S. I didn't get your point about python having nominal types, duck typing seems closer to structural typing to me and mypy seems to support both, but maybe I misunderstood you. Thanks for the thought provoking discussion though :)


> When I am thinking about a REPL the image I have in mind is of Jupyter Notebook and Clojure, Elixir, Idris, Haskell REPLs in Emacs

Thats my point is that the REPL case of using Emacs to run and evaluate your code is almost hardly different than letting an IDE run your unit test. With Java this evident because the IDE compiles incrementally and the debugger can hot code swap.

The power of the REPL should not be the evaluation portion but the input or the print otherwise you can just about do any quick evaluation for any language that compiles reasonable fast.

Other than Jupyter Notebook the ones you mention don't really have any amazing output other than pretty print. To the authors point it also helps for the pretty print if the language is homoiconic.

As for input there is even fewer that have Excel like rapid response feedback. See Bret Victor on this. There was a recent company presented here on HN called Luna [1] who have a very cool REPL. Now that is where I think REPLs should be.

> P.S. I didn't get your point about python having nominal types, duck typing seems closer to structural typing to me and mypy seems to support both, but maybe I misunderstood you. Thanks for the thought provoking discussion though :)

For the most part you need to name functions in Python (lambda support I believe is even on the way out but I can't recall the status). In fact other than I guess tuples you need to name everything in Python.

But to your point structural typing means less in a duck typing environment particularly one with really late dispatch.

[1]: https://news.ycombinator.com/item?id=14612680


> Thats my point is that the REPL case of using Emacs to run and evaluate your code is almost hardly different than letting an IDE run your unit test. With Java this evident because the IDE compiles incrementally and the debugger can hot code swap.

Using a REPL vs. an IDE like you describe is the difference between a conversation and sending somebody a letter with instructions.

This is more visible when we use more dynamic languages/runtimes than Java/JVM. Since the changes one can do and how they need to be done is not very advanced, the usefulness of a REPL is reduced.


I have a feeling given your screen name I'm talking to some who is equally biased as I am to Java :)

> Using a REPL vs. an IDE like you describe is the difference between a conversation and sending somebody a letter with instructions.

Hmmm an IDE is supposed to be a REPL and more. I mean you can go look up the definition from wikipedia.

> This is more visible when we use more dynamic languages/runtimes than Java/JVM. Since the changes one can do and how they need to be done is not very advanced, the usefulness of a REPL is reduced.

Yes I completely agree as I mentioned dynamic languages are far easier to modify at runtime. However for the case with Java it can be done with JRebel and various other tools.

Furthermore going back to the whole conversation vs letter an IDE with a powerful debugger will let you evaluate expressions based on a state that is stuck... ie setting breakpoint (as well of course as investigating current variables and such). This is damn useful for dealing with a multithreaded environment.

By the way make no mistake... I do love Lisp... I just think there are better things than traditional REPLs considering to your other point in another thread this stuff has existed since the 70s.


> I have a feeling given your screen name I'm talking to some who is equally biased as I am to Java :)

The main difference: I have a Lisp Machine at home. :-)

> Hmmm an IDE is supposed to be a REPL and more.

No, a Read Eval Print Loop came from Lisp in the early 60s. It originally means to read a data structure, treat it as code and evaluate it and print the result data structure. READ, EVAL, PRINT are actual functions in Lisp. This stuff executes in a LOOP and is enriched by all kinds of stuff.

An IDE does not need to have a REPL. If it can interact with a running application (for example via a debugger), this might still not be a REPL.

> However for the case with Java it can be done with JRebel and various other tools.

Even JRebel can not do to a running JVM application what some Lisp implementations can do. Not near of that.

> IDE with a powerful debugger will let you evaluate expressions based on a state that is stuck... ie setting breakpoint (as well of course as investigating current variables and such)

This is pretty basic.

> traditional REPLs

Check out Symbolics Dynamic Windows and McCLIM on the Lisp side...

Old demos from me:

https://www.youtube.com/watch?v=VU_ELJjbnWM

https://www.youtube.com/watch?v=9whxPd4haKc

http://lispm.de/videos/lispm-3a.mov


I think I'm in agreement with you. What I meant by the IDE is that "ideally" it should have REPL like offerings if the language can support hot code swapping.

I still don't think its REPL that makes Lisp or clojure magic (when I say magic I mean awesome). Its all the other stuff like macros and homoiconicity (which I see your point plays some part in academic REPL).

> Even JRebel can not do to a running JVM application what some Lisp implementations can do. Not near of that.

Well thats because of the Java compiler and in some parts the language of Java. It has nothing to do with the JVM otherwise Clojure wouldn't work. But I agree JRebel is far cry from the full reloading capabilities of Lisp, Erlang and other dynamic languages.

> IDE with a powerful debugger will let you evaluate expressions based on a state that is stuck... ie setting breakpoint (as well of course as investigating current variables and such)

> This is pretty basic

I agree but its still surprising how many languages do not do this well and I didn't mention that you can execute simple expressions in that mode something other static languages like C will not allow.

Besides.... I can change a function name in Java or Scala and see immediately everywhere in my code base with (e.g. red squiggle lines) how that impacts other code... for static languages that is pretty basic :P

I'm totally envious of your lisp machine (EDIT: in all honesty...I realize that originally sounded sarcastic).


> Well thats because of the Java compiler and in some parts the language of Java. It has nothing to do with the JVM otherwise Clojure wouldn't work.

Clojure is constrained by the JVM and its implementation. Though Java is even more constrained.

You get a mini Common Lisp Object System demo in the LispWorks REPL:

We define a class person with a slot 'name':

  CL-USER 1 > (defclass person () ((name :initarg :name :accessor name)))
  #<STANDARD-CLASS PERSON 402005BA03>
Let's create a list of persons:

  CL-USER 2 > (setf persons (mapcar (lambda (name)
                                      (make-instance 'person :name name))
                                    '("Jan" "Ralph" "Joan")))
  (#<PERSON 40200A493B> #<PERSON 40200A49F3> #<PERSON 40200A4AAB>)
Let's define a custom print method:

  CL-USER 3 > (defmethod print-object ((p person) stream)
                (print-unreadable-object (p stream :type t :identity t)
                  (write-string (name p) stream)))
  #<STANDARD-METHOD PRINT-OBJECT NIL (PERSON T) 40200A942B>

How does a person print now?

  CL-USER 4 > persons
  (#<PERSON Jan 40200A493B> #<PERSON Ralph 40200A49F3> #<PERSON Joan 40200A4AAB>)

Let's add a slot to the class, a slot 'age':

  CL-USER 5 > (defclass person ()
                ((name :initarg :name :accessor name)
                 (age  :initarg :age  :accessor age :initform 0)))
  #<STANDARD-CLASS PERSON 41404737D3>
Let's update the print method:

  CL-USER 6 > (defmethod print-object ((p person) stream)
                (print-unreadable-object (p stream :type t :identity t)
                  (format stream "~a ~a" (name p) (age p))))
  #<STANDARD-METHOD PRINT-OBJECT NIL (PERSON T) 40201289FB>
Woops: all persons now have already got the new slot:

  CL-USER 7 > persons
  (#<PERSON Jan 0 4140473733> #<PERSON Ralph 0 4140473933> #<PERSON Joan 0 4140473D3B>)
Let's set the new slot:

  CL-USER 8 > (mapc (lambda (p age)
                      (setf (age p) age))
                    persons
                    '(23 43 21))
  (#<PERSON Jan 23 4140473733> #<PERSON Ralph 43 4140473933> #<PERSON Joan 21 4140473D3B>)

Let's define a new class: social-security-mixin:

  CL-USER 9 > (defclass social-security-mixin ()
                ((social-security-number :initarg :ssn :accessor ssn)))
  #<STANDARD-CLASS SOCIAL-SECURITY-MIXIN 40200111C3>

Let's add this new class to the superclasses of PERSON.

  CL-USER 10 > (defclass person (social-security-mixin)
                ((name :initarg :name :accessor name)
                 (age  :initarg :age  :accessor age :initform 0)))
  #<STANDARD-CLASS PERSON 41404737D3>
Now we do something really wild: we write an around method for printing:

  CL-USER 11 > (defmethod print-object :around ((p person) stream)
                 (print-unreadable-object (p stream :type t :identity t)
                   (call-next-method)))
  #<STANDARD-METHOD PRINT-OBJECT (:AROUND) (PERSON T) 40200AB8A3>
We redefine the original method just to print the name and age of the person.

  CL-USER 12 > (defmethod print-object ((p person) stream)
                 (format stream "~a ~a" (name p) (age p)))
  #<STANDARD-METHOD PRINT-OBJECT NIL (PERSON T) 40200AC9EB>
Then we define an AFTER method for the social-security-mixin class:

  CL-USER 13 > (defmethod print-object :after ((o social-security-mixin) stream)
                 (format stream " ~a" (ssn o)))
  #<STANDARD-METHOD PRINT-OBJECT (:AFTER) (SOCIAL-SECURITY-MIXIN T) 402001917B>
Now we set the social security number of the persons. Wait? Lisp has updated my objects, since I added a new superclass to their class? All objects now have a changed superclass for their class? They inherit the new slot?

And the print-method gets reassembled for the new inheritance tree and the changed set of methods?

  CL-USER 14 > (mapc (lambda (p ssn)
                      (setf (ssn p) ssn))
                    persons
                    '("123-345" "321-455" "443-222"))
  (#<PERSON Jan 23 123-345 4140473733> #<PERSON Ralph 43 321-455 4140473933> #<PERSON Joan 21 443-222 4140473D3B>)
As you see the objects have a SSN and the print methods are dynamically combined. For the person it runs the around method, then the primary method of person and then the after method of the mixin. If I'd now change the inheritance tree, then the methods would be recombined according to the inheritance at runtime... I could also dispatch on the second argument...

CLOS supports multi-dispatch over multiple-inheritance with dynamic combinations of applicable methods.

CLOS can do quite a bit more than that...

Java can't do anything like that.

It can't update objects on class changes/inheritance changes/...

It can't combine methods based on the multiple-inheritance class tree.

It can't change the class of objects. It can't reprogram the object system itself. See the CLOS MOP...


Yes CLOS is superior particularly multimethods.

As for the JVM: https://common-lisp.net/project/armedbear/

Sooo its not the JVM.

BTW AspectJ and JRebel will get you around methods and even inheritance changes but alas Java does not have multimethods or MOP. I mean CLOS is awesome but so is static analysis :)


ABCL implements CLOS classes in Java. It does not use the Java/JVM directly. For example a CLOS class is an instance of some Java class. This instance then has an attribute which has a vector of the CLOS slots. CLOS slots are not Java attributes themselves... The JVM object model is simply not able to provide CLOS features directly.

Last I've looked Jrebel used a funny mechanism. One couldn't just tell the class to add a slot, but one has to have Jrebel installed and given a new class file, it will detect it and then change/load the class...

That's a rather limited mechanism aimed at development... especially since it needs a license to work...


I have to agree about Java, but hundreds of thousands of people seem to be happy using Python REPL, even if just to discover an API. At least it _does_ have a literal syntax for things like maps.


Yeah the Python one was a stretch and I often use the Python REPL as a calculator (I have no real strong idea why but I guess because numpy is what I know).




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

Search: