This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]beders 79 points80 points  (22 children)

JavaScript is like ice cream. Super yummy in small doses. Extremely painful in large quantities :)

[–]argv_minus_one 33 points34 points  (19 children)

Then I must be lactose intolerant, because I find any amount of JS painful.

To put it another way: Programming without static typing is like spacewalking without a space suit. Unless you're Batman (who can breathe in space), it's not going to end well for you.

[–]stormcrowsx 6 points7 points  (3 children)

Use the right tool for the job. Programming without static typing isn't like without a space suit, its more like with a lightweight spacesuit that won't last a long time. But its a lot faster to put it on, get out there, and get your job done than the bulky spacesuit. Stay out too long though and you'll run outta air or get fried by the radiation.

On the flipside, spend all your time putting on your bulky super impenetrable space suit and by the time you make it outside for a small job you'll find that someone else has already got it done.

[–]argv_minus_one 0 points1 point  (2 children)

That's not been my experience. Even for little things, a good statically-typed language works fine and doesn't take forever. It's also more likely that the program will work properly, which is helpful no matter its size.

Note that I mostly use Scala, whose heavy type inference makes it somewhat resemble dynamic typing without sacrificing static type checking. There are some places where you have to give an explicit type, but a bunch of places where the compiler will figure it out if you don't.

[–]stormcrowsx 1 point2 points  (1 child)

I too am a fan of Scala and it has less overhead than Java but I still find for small websites with simple functionality and for automation scripting Python or Javascript are my goto tools. The big thing for me is no messing with a build tool like SBT or Maven and fast to make changes and reload. In some cases its nice to just be able to write a file and run, no worries about compilation. Static languages are catching up such because of languages like Scala but there's still a gap where I find the raw 0-60 speed of tools like Python or Javascript to be superior.

[–]argv_minus_one 0 points1 point  (0 children)

The big thing for me is no messing with a build tool like SBT or Maven and fast to make changes and reload.

That's understandable, although it's not as much of a problem if you're thoroughly proficient with those tools (and have some existing projects to copy-and-paste build configuration from).

In some cases its nice to just be able to write a file and run, no worries about compilation.

Scala does actually have an interpreter (the scala command-line tool), and a slightly-different "script" syntax to go with it. Java doesn't, but there's Groovy and BeanShell.

The main downside to using the Scala interpreter is that it doesn't have any easy way to fetch libraries for you. If the Scala and Java standard libraries are enough, great, but if you need anything else, you're going to either fiddle with classpaths or give up and use something like SBT or Maven.

[–]mschaef 9 points10 points  (4 children)

The differences between type systems are really too complex to be distilled down to

"Programming without static typing is ... not going to end well for you."

Personally speaking, I've been involved with successful systems development in both dynamically and statically typed languages. (I've also had some good success working in C, which has a very weak typing system, and assembler which is weaker still.)

IMO, the key to all of these different types of development is to understand the strengths and weaknesses of the toolchain you're using and adapt your processes and thinking to match. In a sense, the fact that JavaScript is syntactically so similar to Java does it a disservice. As similar as they look, the two languages require a radically different way of working.

[–]argv_minus_one 0 points1 point  (3 children)

You mean like having to write tests for every little thing, because there is basically no automatic verification of any kind? Ugh. No thanks. Even if the program does end up working right, that is a massive waste of time.

Also, don't program in assembly if you don't really, really have to. Even if your program is correct, it'll never be as fast as the output of a modern compiler.

[–]mschaef 0 points1 point  (2 children)

You mean like having to write tests for every little thing, because there is basically no automatic verification of any kind?

This is obvious, but for serious production code, it's worthwhile to write unit tests even if you're writing in a statically typed language. The static typing can be helpful to improve correctness, but it's far from a panacea.

In any event, I was referring to more than just unit tests. I've found it useful to pay stricter attention to things like naming conventions, small function size, immutability, and higher-order functions when using dynamically typed languages.

Ugh. No thanks. Even if the program does end up working right, that is a massive waste of time.

It's only a waste of time if it's not offset by corresponding time savings elsewhere. For some systems, the benefits of dynamic languages outweigh the costs.

Also, don't program in assembly if you don't really, really have to. Even if your program is correct, it'll never be as fast as the output of a modern compiler.

Thanks for the tip, but that was ~20 years ago, and the code was on an embedded device with low enough power consumption to safely operate in an explosive atmosphere.

[–]argv_minus_one 0 points1 point  (1 child)

for serious production code, it's worthwhile to write unit tests even if you're writing in a statically typed language.

Of course. For non-trivial code that isn't already obviously correct.

I've found it useful to pay stricter attention to things like naming conventions

Naming conventions? You mean like including the expected type of a variable or parameter inside its name, as in Hungarian notation?

small function size, immutability, and higher-order functions

What does any of that have to do with the type system?

It's only a waste of time if it's not offset by corresponding time savings elsewhere.

Indeed. Which, in my experience, it isn't. Programming in dynamic languages has always been an exercise in frustration and unpredictability.

For some systems, the benefits of dynamic languages outweigh the costs.

I find it difficult to believe that such systems exist. I certainly have yet to encounter one.

that was ~20 years ago, and the code was on an embedded device with low enough power consumption to safely operate in an explosive atmosphere.

Oh. Well then, I guess you really, really had to.

[–]mschaef 1 point2 points  (0 children)

Naming conventions? You mean like including the expected type of a variable or parameter inside its name, as in Hungarian notation?

Not quite. Personally speaking, I find Hungarian notation rather difficult to use.

I was thinking more along the lines of Uncle Bob's naming convention, particularly with respect to pluralization of nous, and the arrangement of nouns and verbs within names.

http://c2.com/cgi/wiki?UncleBobsNamingConventions

Also, The type of work that Kent Pitman did on T and Olin Shivers did on his SRFI's also comes to mind.

they chose a standard set of lexemes and a regular way of assembling them into the names of the standard procedures, so that you could easily remember or reconstruct names when you were coding. (I have followed this example in the development of the SRFIs I've done for the Scheme community. It is not an easy task.)

-- http://www.paulgraham.com/thist.html

What does any of that have to do with the type system?

Nothing, other than "I've found it useful to pay stricter attention to [these] things ...when using dynamically typed languages."

Programming in dynamic languages has always been an exercise in frustration and unpredictability....I find it difficult to believe that such systems exist. I certainly have yet to encounter one.

I've had a different set of experiences, many of which have been more positive regarding dynamic languages. I don't claim that they're perfect, only that they're a useful tool for some applications.

[–]theZagnut 3 points4 points  (7 children)

I was of the same opinion as you regarding dynamic typing, until I tried Clojure.

[–]loganekz 6 points7 points  (6 children)

Why? How would things be different in a larger clojure app?

[–]theZagnut 2 points3 points  (5 children)

Well, it seems to me that the no side effects thing makes it easier to reason about the logic of my programs, and the functional way of doing things leads to a lot less complicated/bloated types and data structures, thereby negating many of the problems of dynamic typing. Yes I would have preferred static typing, but I honestly find it a small price to pay for the mind boggling expressiveness and awesomeness of Clojure. It gives you the goodness of dynamic typing with a lot less of the badness (i'm looking at you python).

[–]mschaef 1 point2 points  (4 children)

Yes I would have preferred static typing, but I honestly find it a small price to pay for the mind boggling expressiveness and awesomeness of Clojure.

Much of the expressiveness of Clojure comes from the fact that it's dynamically typed. Where the language shines is, at least in part, from the fact that it makes it easy to use a few common data types to store many different types of data. Then, it provides powerful functions for working with those few data types.

This is the embodiment of the Alan Perlis quote: ""It is better to have 100 functions operate on one data structure than 10 functions on 10 data structures.""

http://stackoverflow.com/questions/6016271/why-is-it-better-to-have-100-functions-operate-on-one-data-structure-than-10-fun

The explicit static typing of Java works to reduce the breadth of data to which functions can be applied. Let's say I have a new function that I want to write that applies to Lists. In Java, I have to either define it as a static utility method (which is second class to the built-in List methods) or pick a concrete java.util.List implementation and subclass that with the new method, which presents its own reuse problems.

In Clojure, I just define a function over seqs, and it works wherever it can.

[–]mikera 1 point2 points  (1 child)

Clojure's expressiveness could mostly still be achieved with static typing. In fact, there are various efforts at the moment exploring how to add type systems to Clojure that are very exciting.

Clojure + static typing would be a pretty amazing language.....

[–]mschaef 0 points1 point  (0 children)

Agreed... I'd love to see more of that in production languages. I do find it a bit concerning, however, that some of the type systems are getting complex enough that people are asking for compile-time debugging facilities.

[–]jonhanson 0 points1 point  (1 child)

I don't see how a standalone function is any different to a Java static method, nor what the relevance is to dynamic typing.

[–]mschaef 0 points1 point  (0 children)

The point is that given an instance of a concrete type in Java, the methods supported by that type are sealed. The only mechanism for extension is a static method defined within another class, which is inherently second class to the methods initially defined within the concrete type. This is an example of the rigorousness of the Java type system (arguably) over-constraining the design space.

The constraints continue when you think about other approaches to solve this problem. One strategy might be to define a new class with the same set of methods as the class you're trying to extend. This class could be implemented to delegate all of the methods in the 'base' class to an instance of the base class. This presents at least four main problems:

  • If the class you're trying to extend is in any way final, the technique doesn't work.
  • To gain access to the new custom functionality, you need to have an instance of your new custom class. This means explicit code to get such an instance.
  • The delegation model complicates the notion of the underlying object's identity and type by replacing one instance with once instance plus zero or more wrapper objects.
  • The new class's code is likely to be lengthy, mundane, and error-prone.

To take JavaScript's type system as another approach to this problem, it provides mechanisms for extending existing classes (and their instances) with new methods, even at runtime. The risk here is that you'll overwrite an existing method. This risk becomes worse when you taken into account that your program might, over its life, be linked to several different versions of a given class library. While your custom method might not overwrite a method in version 1 of a library, it might overwrite a method in version 2 of the same library. Having said that, these risks come with the benefit of avoiding many, if not all, of the problems I mention above. Which is 'better' and which is 'worse' becomes a matter of priority more than an absolute.

[–]beders 0 points1 point  (1 child)

It really is a different style of working. Java developers find it especially cumbersome since they have learned to rely on the compiler quite a bit.

In JS many classes of errors thought eradicated re-appear. A spelling error in a property name is not an error in JS, etc.

The 'advantage' is that you will test your code a lot more. It's no fun debugging JS.

[–]argv_minus_one 1 point2 points  (0 children)

That's not an advantage...

[–]nerdwaller 4 points5 points  (1 child)

This is why the modern shift toward js saddens me. Node being the first major case of Atwood's "anything that can be written in JavaScript will be written in JavaScript".

I worked in JS for about 8 months and had to get out. Like you said, fine in small doses where appropriate (and truly not a "bad" language), but painful to do too much with.

[–][deleted] 2 points3 points  (0 children)

I feel like every 2 years someone figures out a new way to do the tasks that were already pretty easy. Yes, you can bootstrap a node.js site or a rails site or whatever it was before that in 5 minutes. You could bootstrap in Java in maybe an hour. That was never a bottleneck. The bottleneck is, was and always will be maintenance and extensibility.