Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

The question is in the title. I want to have my thinking verified by experienced people. You can add more or disregard my opinion, but give me a reason.

Here is an example requirement: Suppose you are required to implement a fighting game. Initially, the game only includes fighters, who can attack each other. Each fighter can punch, kick or block incoming attacks. Fighters can have various fighting styles: Karate, Judo, Kung Fu... That's it for the simple universe of the game. In an OO like Java, it can be implemented similar to this way:

abstract class Fighter {
    int hp, attack;

    void punch(Fighter otherFighter);
    void kick(Fighter otherFighter);
    void block(Figther otherFighter); 
};

class KarateFighter extends Fighter { //...implementation...};
class JudoFighter extends Fighter { //...implementation... };
class KungFuFighter extends Fighter { //...implementation ... };

This is fine if the game stays like this forever. But, somehow the game designers decide to change the theme of the game: instead of a simple fighting game, the game evolves to become a RPG, in which characters can not only fight but perform other activities, i.e. the character can be a priest, an accountant, a scientist etc... At this point, to make it more generic, we have to change the structure of our original design: Fighter is not used to refer to a person anymore; it refers to a profession. The specialized classes of Fighter (KaraterFighter, JudoFighter, KungFuFighter) . Now we have to create a generic class named Person. However, to adapt this change, I have to change the method signatures of the original operations:

class Person {
    int hp, attack;
    List<Profession> skillSet;
};

abstract class Profession {};

class Fighter extends Profession {         
    void punch(Person otherFighter);
    void kick(Person otherFighter);
    void block(Person otherFighter); 
};

class KarateFighter extends Fighter { //...implementation...};
class JudoFighter extends Fighter { //...implementation... };
class KungFuFighter extends Fighter { //...implementation ... };

class Accountant extends Profession {
     void calculateTax(Person p) { //...implementation...};
     void calculateTax(Company c) { //...implementation...};
};
//... more professions...

Here are the problems:

  1. To adapt to the method changes, I have to fix the places where the changed methods are called (refactoring).

  2. Every time a new requirement is introduced, the current structural design has to be broken to adapt the changes. This leads to the first problem.

  3. Rigid structure makes it hard for code reuse. A function can only accept the predefined types, but it cannot accept future unknown types. A written function is bound to its current universe and has no way to accommodate to the new types, without modifications or rewrite from scratch. I see Java has a lot of deprecated methods.

OO is an extreme case because it has inheritance to add up the complexity, but in general for statically typed language, types are very strict.

In contrast, a dynamic language can handle the above case as follow:

;;fighter1 punch fighter2
(defun perform-punch (fighter1 fighter2) ...implementation... )

;;fighter1 kick fighter2
(defun perform-kick (fighter1 fighter2) ...implementation... )

;;fighter1 blocks attacks from fighter2
(defun perform-block (fighter1 fighter2) ...implementation... )

fighter1 and fighter2 can be anything as long as it has the required data for calculation; or methods (duck typing). You don't have to change from the type Fighter to Person. In the case of Lisp, because Lisp only has a single data structure: list, it's even easier to adapt to changes. However, other dynamic languages can have similar behaviors as well.

I work primarily with static languages (mainly C and Java, but working with Java was a long time ago). I started learning Lisp and some other dynamic languages this year. I can see how it helps improving my productivity.

share|improve this question
9  
I feel like there's a good question in here somewhere, but I can't tell exactly what it is. –  KChaloux Dec 11 '12 at 15:01
1  
Well, I put it at the very first sentence :) –  Amumu Dec 11 '12 at 15:13
    
Initially, I want to keep the question short. I just want to ask about the advantages of having no type in dynamic languages for dynamic requirements. But then, it will hard to discuss without a concrete example for everyone as a baseline for the discussion. –  Amumu Dec 11 '12 at 15:32
8  
You seem to be under the impression that refactoring Dynamically typed languages is easier than Statically typed ones, because you won't have the compiler throwing up errors at you if a type needs to change. In my experience, it's the opposite. A dynamic language will begin interpreting sooner after the refactor, but there were be a lot of logical errors that will be very hard to find without significant testing, that could otherwise have been picked up by the compiler. As for avoiding rewriting large amounts of code, sometimes you can't. Implementation has to change with the logic. –  KChaloux Dec 14 '12 at 14:05
3  
Refactoring is not a "problem". It's part of the software development process. –  user61852 Dec 17 '12 at 15:54
show 9 more comments

closed as unclear what you're asking by gnat, GlenH7, Dynamic, MichaelT, Bart van Ingen Schenau Jan 29 at 9:54

Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question.If this question can be reworded to fit the rules in the help center, please edit the question.

5 Answers

I am not entirely sure what your question is, because it the question includes a number of vague terms: "dynamic language", "this" and "dynamic requirement".

"Dynamic language" can refer to any programming language that does something that other languages may do at compile time. This can include aspects of data values (null or not null), aspects of the type system (e.g. creating new types at runtime), aspects of method and function dispatch and many other aspects. Your question seems to be primarily concerned with dynamic method dispatch (although you talk about static typing later on). My attitude to this would be that different languages provide one with different tools of how to deal with requirements and also with changing requirements. In that sense, the answer to your question is probably "yes". Where languages like Java or Scala provide interfaces and traits to make it easier to adapt the design of your programs to changing requirements, a language like Clojure provides dynamic dispatch, Groovy provides metaprogramming and still other languages provide no or very little tools at all. I think which of these tools are better suited for the task depends on the details of the task, the details of your definition of "better" (development time and effort, availability of programmer, performance of code, likelihood of certain classes of bugs during runtime etc.) and on personal preference and cannot be answered in general.

share|improve this answer
2  
"Dynamic language" is more of a marketing term. Now statically typed languages like Scala and C# has a dynamic keyword, they are now dynamic languages! –  Vorg van Geir Apr 3 '13 at 14:26
    
@VorgvanGeir I'd say C# is a static language with some support for dynamic language features. –  Andy Jan 28 at 18:00
add comment

A dynamic language can be great when faced with dynamic requirements. Personally, I prefer Python to C when I'm faced with a lot of changes. There is far less ceremony compared with C++, C#, Java. But ...

Regardless of the language, the architecture of the system / project has a massive impact upon how well we can adapt to changes, such as those that you mention. For me the bigger question is "How quickly can we refactor to accommodate the changes." For your example, base classes would need changes and I would prefer to have multiple inheritance.

In our projects, the external analysis and design documents are massively revisited when big changes come about. We prefer to issue revised documents and from that make a big list of change requests. And yes, the test suites need a lot of extra work too.

share|improve this answer
add comment

I think the answer boils down to: yes a "dynamic" language helps your coding productivity as you can make sweeping changes quickly and easily. However, it hurts your release productivity as you have create a mess of code that has no consistent structure to it and lots of only-runtime-detectable errors that will need fixing later, rather than sooner like you'd get in a "static" language.

There's simply no substitute for doing things correctly, and that means thought, design, and careful consideration of the impact of your changes.

share|improve this answer
add comment

I'm not sure, I'm getting your point here, but different kinds of languages don't really solve the underlying problem which is, basically, that a once written code base needs to be expanded. While this is something that refactoring, obviously, can solve, maybe the general concept/design of the code was unfortunate in the first place.

For instance, how about a Fighter (or a Person if you later change that) does "just something". Using, for example Java generics, you can even limit what they can do.

class Fighter {
    void doSomething(Command<? extends FighterCommand> cmd) {
        cmd.execute();
    }
}

One can now easily, at any point during development, expand the abilities of a fighter by just adding another command.

class KickCommand extends FighterCommand {
    @Override
    public void execute() {
        kickSomeone();
    }
}

Using the Command pattern here would absolve you from changing interfaces all over the place just because the fighter needs to punch someone now, too.

And getting closer to what you were asking, extending the Fighter concept to a Person concept should be possible by making the Fighter extend (the now new) Person. If a Person can doSomething(), too, it's only one @Override in the Fighter away (or deletion of the Fighter method :)).

share|improve this answer
add comment

A dynamic language may complain less when you refactor, but it could also be hiding type errors from you that you'd catch at compile time on a statically typed language. In general, you'll have to refactor your code when your requirements change regardless of whether you're on a dynamic or statically typed language. There's no silver bullet there.

C and Java aren't good benchmarks for static languages, because they have very limited type systems and features. You can't get anything done in Java without extreme verbosity. Want to pass a tuple? Well, you can't. Records? You can't. Want an anonymous function? You'll have to write 4 lines of boilerplate for a payload that could be as short as 2 + 2. God help you if you want to curry or compose functions.

You have to resort to a bunch of OO hacks to work around those missing features, and even then you can still shoot yourself in the foot with inheritance and null because so many people don't understand how dangerous they are. So if that's your only point of reference, just about any dynamic language will allow you to write less code, but not necessarily by virtue of their dynamic typing. Languages like Standard ML or F# also provide those features without burdening you with type annotations because the compiler can infer the types.

A good statically-typed language is more expressive than a dynamically typed language with equivalent features. Dynamic typing deprives you of the ability to express constraints on your data using the type system. That's because dynamic typing is a special case of static typing - it's more correct to think of these languages as being unityped. If that seems strange to you, imagine coding in Java using only Object variables and casts. The problem is that mainstream statically typed languages are crippled. But if you're coding in Lisp, I don't think you're too concerned with what's mainstream.

share|improve this answer
add comment

Not the answer you're looking for? Browse other questions tagged or ask your own question.