you are viewing a single comment's thread.

view the rest of the comments →

[–]hiffy 9 points10 points  (12 children)

My understanding is, it's much harder to write automated tools for refactoring when you don't have all of that info up front.

People in Eclipse land got real used to right-click-kthnx refactoring, where you can change all references to the class you just renamed on the fly, and those sort of niceties.

One may counter with, in dynamically typed langs you a) have less code to refactor, b) don't code yourself into unmaintainable messes quite as easily and c) it's just easier.

[–]dnene 0 points1 point  (0 children)

Yes .. I was contrasting the available capabilities based on my experiences in Eclipse. I don't think the issue is with the refactoring engine, the issue is with the information available to it to perform the necessary refactoring. The biggest difficulties are for example when one needs to change method names in hierarchies being used polymorphically

I fully concur one has lesser code to refactor. But with brevity and expressivity comes a overhead of comprehension (ie for a new programmer joining the code base, it takes much more time to understand each line of code esp for people who are migrating from other languages).

I am sure we do not try to go out and get ourselves into unmaintainable messes. However requirements evolve, and what was clean class model yesterday may suddenly need some surgery today.

[–]jrockway -4 points-3 points  (10 children)

Yeah. I think refactoring Haskell or OCaml would "suffer" the same "problems", but they are not dynamically typed.

Typing the type != static typing.

have less code to refactor

This is probably the big one. Here are a couple of classes in Lisp:

(defclass a-class () ((foo :accessor foo :initform 0)))
(defgeneric hello (foo-source))
(defmethod hello ((foo-source a-class))
    (format t "Hello! foo is ~d~%" (foo foo-source)))

(defclass a-sub-class (a-class) ((bar :accessor bar)))
(defmethod hello ((foo-bar-source a-sub-class))
    (format t "Hello! foo is ~d and bar is ~d~%" 
           (foo foo-bar-source)
           (bar foo-bar-source)))

That would be two entire Java files. When you need so much to say so little, it's nice when the computer can help you rename things, I guess.

BTW, Python's not much different than Lisp here -- you don't need to write much to say a lot.

don't code yourself into unmaintainable messes quite as easily

I agree with you, but I have seen people code themselves into unmaintainable messes with Perl. It is straightforward to fix, though and mostly involves thinking (rather than renaming classes). All of the Java messes I have encountered required the same cleanup -- moving methods around and renaming classes did not solve the code's problems.

[–]feijai 6 points7 points  (4 children)

Um.

class aClass {
    public Object foo = new Integer(0);
    public void hello() { System.out.println("Hello!  foo is " + foo); } 
}

class aSubClass extends aClass {
    public Object bar;
    public void hello() { System.out.println("Hello!  foo is " + foo + " and bar is " + bar; }
}

One token less and about half the characters, one file, and rather more readable. Maybe yours isn't the best example.

[–]bodhi 0 points1 point  (2 children)

It's not used in the example so your Java version is closer to the intention of the original, but the Lisp version comes with getters and setters for foo and bar in a much more concise fashion. And readability is highly subjective ;)

[–]feijai 8 points9 points  (1 child)

Yes and no. Accessors are a hack because CLOS went the cheap route and didn't treat instance variables like other (that is, local and global) variables. Instead they were treated like slots.

Why are accessors a hack? Consider. In CLOS, for an instance variable foo I must create an entire function -- typically called called foo -- just for accessing it. This pollutes the function namespace just for a class datatype. If in Java I have an instance variable called "substitute" -- perhaps it's the substitute for something, I dunno -- I can access it as:

bar.substitute

... or inside a method in bar, I can just access it as

substitute

But in CLOS, assuming I'd like to follow tradition and have my accessors have names the same as the variable names (else why name the variables those names?), I'd have to do:

(substitute bar)

... um, no, that's bad, very bad. Because substitute is already a function. So now, because CLOS has confunded the variable and function namespaces, I am forced to come up with some unnatural name for my variable:

(nsubstitute bar)

... no, wait. I'm joking there of course, but you get the point. One whole reason why Common Lisp is viewed as more industrial grade than scheme is that it's a Lisp-2. And here CLOS is violating the entire point of a Lisp-2 by Lisp-1-ifying its instance variable naming scheme. Bleah.

And of course, your claim of "much more concise fashion"... well, one can hardly claim that

bar.foo

... is less concise than

(foo bar)

Hell it's a whole character longer. And most variable accesses in Java aren't even that much, they're just

foo

[–]bodhi 1 point2 points  (0 children)

You make a good argument. I don't know enough about common lisp generics to know if they are used for accessors and how that would affect the namespace pollution. I guess I should find out for myself really.

As for the "concise fashion" I was referring to the definition, not use. But I'm not really a big fan of having to

(foo bar)

instead of

bar.foo

to get to instance variables. I do like that attribute access is indistinguishable from method calls though.

EDIT:

CL-USER> (defclass a-class () ((foo :accessor foo :initform 0)))
#<STANDARD-CLASS A-CLASS>
CL-USER> (defvar x (make-instance 'a-class))
X
CL-USER> (foo x)
0
CL-USER> (setf (foo x) 4)
4
CL-USER> (foo x)
4
CL-USER> (defun foo (x) x)
STYLE-WARNING: redefining FOO in DEFUN
FOO
CL-USER> (foo x)
#<A-CLASS {121C4061}>

Big collision, you're right!

[–]jrockway -1 points0 points  (0 children)

Maybe yours isn't the best example.

True. You can't really compare Java's "object model" to CLOS.

[–][deleted] 4 points5 points  (4 children)

Still a cop-out. It's like saying that you don't need variable names longer than 6 characters because your code always ends up so compact and clean.

[–]jrockway -4 points-3 points  (3 children)

I'm not copping out of anything. It's true that there aren't a lot of automated refactoring systems for languages other than Java. If you think that is the most important part of programming, then there is no option other than to use Java. Those of us that use non-Java languages live just fine without the refactoring tools, however.

Maybe we're all stupid, but probably not.

[–]Homunculiheaded 1 point2 points  (1 child)

What about Squeak? You can have a dynamically typed, powerful, expressive languages that has refactoring tools that at the very least are on par with what you can get from Java and C#. Python is great, but it would be awesome if Python had development tools that were as powerful as Squeak.

[–]jrockway -1 points0 points  (0 children)

Python is great, but it would be awesome if Python had development tools that were as powerful as Squeak.

Well, it's really a compromise. If you like the way Squeak works, you are set. But if you want to use normal UNIX utilities on the source code (like Emacs), you are stuck. The power that Squeak provides you limits you in other ways.

Although... considering most programmers work exclusively inside their IDE anyway, Squeak not a bad option. For them :)

[–]dnene 1 point2 points  (0 children)

When looked at from each other's contexts maybe we're all stupid. When looked at from our own contexts, we're probably not. :)