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 Wikipedia article on prototype-based languages contains the following paragraph:

Almost all prototype-based systems are based on interpreted and dynamically typed languages. Systems based on statically typed languages are technically feasible, however.

In what ways does a static type system impose restrictions or introduce complexity in prototype-based language, and why are there more dynamically-typed prototype languages?

share|improve this question
2  
+1 and fav'd: I've been pondering that myself for quite a while, and didn't find any extraordinarily hard problems with a structural type system. In fact, this bothers me so much that I want to ahead and try to create a statically-typed prototype-based language just to see what problems there are... –  delnan Jul 22 '11 at 12:45
    
I'm just beginning that process myself for the same reason :) –  Joe Jul 22 '11 at 12:52
add comment

3 Answers

The border between a fundamental type and an object is blurred and often artificially introduced. For example, In C a struct is just a bunch of records, just a derived non-object type. In C++, a struct is a class with all fields public, an object. Still, C++ is almost totally backwards compatible with C... the border is really soft here.

For prototype-based programming you need to have objects mutable at runtime. They MUST be soft-typed because each changes at runtime, a class of one kind changes into another - its type changes.

You might keep fundamental and derived non-object types as static though. But this introduces a weird disparity, objects are soft-typed, non-objects are static-typed, and a hard barier must be established between the two. Should you be able to morph a structure? A String? Should Number be a class or a fundamental type, or a set of fundamental types, int/float/bignum/etc?

It is just more natural and easy to learn, use and write to have this uniform, all types are mutable or no types are mutable at runtime. If you declare only one type (Object) is mutable, you end up with headaches and problems of both worlds.

Static-typed is:

  • easier to implement
  • faster / more efficient
  • safer
  • easier to maintain/document big systems due to abstraction.

Dynamic-typed is:

  • faster to write in,
  • more concise
  • language easier to learn
  • more forgiving for design errors.

By blending the two, you sacrifice a lot.

  • Implementation becomes harder than any of the previous two.
  • speed depends if you use the soft types or not... If you do, it's low, if you don't, why pick the language at all?
  • type safety is out the window for all object types.
  • following how one type morphs into another is a pretty difficult task. Documenting it - very hard.
  • You still need to do all the bookkeeping with fundamental types, which kills conciseness and writing speed
  • The language complexity is higher (more difficult to learn) than any of the "specific" ones,
  • "forgiving" of a dynamic-typed is replaced by tendency to some very tricky errors at mismatching attribute types.
share|improve this answer
1  
Mind to provide an example why objects need to be "mutable" (I assume you mean addition and removal of attributes, not changing those, as that's usually unrelated to typing). –  delnan Jul 22 '11 at 15:25
    
@delnan: not really, in prototype-based programming you can dig in the guts of an object as you see fit, remove, add, replace, cover, both methods and attributes on a live instance. That's the whole point and a very convenient, flexible replacement for modifying objects through rigid rules of classic inheritance. If a language uses a Class as a Type, you can't modify its structure on the fly if the type is not soft. –  SF. Jul 22 '11 at 19:02
1  
I don't think so. By the same logic, one could argue that class-based programming needs the same freedoms as dynamic class-based languages allow this. No, static prototypes with a structural type systems would annotate objects with a list of its members and recursively their types, and statically check that these members exist (and have the right type) by requiring that all members are given upon object creation or present in the prototype and simply not including a way to remove members. The result still looks pretty prototypish to me and guarantees that each member is present at all times. –  delnan Jul 22 '11 at 19:11
    
@delnan: You just described classic inheritance through composition. Yes, it looks pretty prototypish and is a (very nerfed) way of doing prototype-based programming in a classic inheritance model language. It just strips p-b.p of 90% of the fun, killing its greatest advantages (and simultaneously removing greatest dangers). Yes, in the old foot-shooting analogy, fully-featured p-b.p will help you shoot off both your legs with a tea spoon. If you don't like this kind of power, you'd better stick to classic inheritance. –  SF. Jul 22 '11 at 19:58
1  
You confuse "dynamic" with "prototypes". These freedoms which don't blend well with static type systems aren't features of prototypes, they are features of dynamism. Of course adding static typing prevents them, but they aren't part of prototypes (that's IMGO mainly lack of classes in favour of cloning objects to act as parents). That dynamism is orthogonal to prototypes. All popular prototype languages happen to include them, but they are independent of prototypes as stated before. Consider this snippet in a fictional language: pastebin.com/9pLuAu9F. How is it not prototypes? –  delnan Jul 23 '11 at 10:29
show 7 more comments

The difficulty is pretty straightforward to see: Taking the view of objects as dictionaries of methods, or as things that respond to messages, observe the following about common statically-typed OO languages:

  • All dictionary keys/messages are generally declared in advance, using statically-declared identifiers.

  • Certain sets of messages are declared in advance, and objects are associated to these sets to determine which messages they respond to.

  • Inclusion relationships of one set of messages being a subset of another are declared statically and explicitly; undeclared but logical subsets aren't valid.

  • Type-checking attempts to ensure that all messages are sent only to objects that respond to them.

Every one of these conflicts to some extent with a prototype-based system:

  • Message names could be declared in advance, in the form of "atoms" or interned strings or whatnot, but little else; the plasticity of objects means that assigning types to methods is awkward.

  • It's arguably the essential feature of a prototype-based system that sets of messages are defined by what an object responds to, rather than the other way around. It would be reasonable to assign aliases to particular combinations at compile-time, but message sets determined at runtime must be possible.

  • The real impact of the above two hits home with inclusion relationships, where explicit declarations are completely unworkable. Inheritance in the static, nominal subtyping sense is antithetical to a prototype-based system.

Which brings us to the final point, which we don't actually want to change. We'd still like to ensure that messages are only sent to objects that respond to them. However:

  • We can't know statically what messages may be grouped together.
  • We can't know which groupings are subsets of others.
  • We can't know which groupings are possible.
  • We can't even specify what kind of arguments are sent along with a single message.
  • Basically we've found we can't specify much of anything at all in the fully general case.

So how can this be worked around? Either limit the full generality somehow (which is unpleasant, and can quickly kill any benefits of using a prototype-based system in the first place), or make the type system much more fluid and express constraints rather than exact types.

The constraint-based type system quickly leads to the notion of structural sub-typing, which in a very loose sense can be thought of as the static equivalent of "duck typing". The biggest obstacles here are that such systems are much more complicated to type check, and are less well-known (which means little prior work to study).

In summary: It's possible, it's just harder to do than either a nominal static type system or a dynamic system based on runtime metadata, and therefore few people bother.

share|improve this answer
add comment

I believe a way to achieve a statically-typed, prototype-based language would be to base the language around Templates and Concepts.

Concepts were once a planned feature for C++0x. Generic code in C++ templates is already de facto "statically duck-typed". The idea of Concepts is to be able to say some things about required members and characteristics of types, without requiring or implying a class-inheritance model underlying that relationship (because it had to work with existing template code that was already "statically duck typed").

In a language based from the ground-up on Templates and Concepts, it would be the Concepts that are prototype-based, and Templates would free you from caring about any class model which may or may not be used to implement the types of values.

Aside from tricks of using staged-compilation to allow the language to be its own meta-language, these prototypical derivations of Concepts would necessarily be immutable once created. However, the objection that that is not prototype-based is a red herring. It would simply be a functional language. A dynamic prototype-base language that is also functional has at least been attempted.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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