The Artima Developer Community
Sponsored Link

Weblogs Forum
Is Static Typing a Form of Bad Coupling?

74 replies on 5 pages. Most recent reply: Apr 23, 2006 1:52 PM by Isaac Gouy

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 74 replies on 5 pages [ « | 1 ... 2 3 4 5 ]
Vesa Karvonen

Posts: 116
Nickname: vkarvone
Registered: Jun, 2004

Unwritten rules: multi-sorted abstractions Posted: Apr 14, 2006 5:40 AM
Reply to this message Reply
Advertisement
I know of many designs where they are unwritten rules like "instances of class B are only used in class A or it's subclasses.

[BTW, monads are one of the techniques used to provide guarantees similar to that one.]

This reminds me of one huge deficiency in the type systems of Java and C++. Essentially, the Java and C++ type systems, which are based on the traditional single-dispatch ideology of OO, can not easily express multi-sorted abstractions ("multi-sorted" as in "multi-sorted algebra"). In other words, an interface or a class in Java/C++ is only abstract with respect to a single type. However, abstractions are frequently multi-sorted, meaning that you need multiple abstract types ("sorts") to properly express the abstraction. You really can't express such abstractions in Java and C++ properly.

Consider an API for 3D graphics hardware. Direct3D is one such API. As a whole, it provides an abstraction of the 3D rendering hardware. The Direct3D API consists of several interfaces including "VertexBuffer" and "Device". The idea is that VertexBuffers and Devices may only be created by the Direct3D implementation. More specifically, an implementation of the Device interface only expects implementations of VertexBuffer that have been created by the Direct3D implementation. However, the C++ type system can not directly express this sort of multi-sorted constraints. A user of the Direct3D API can write a mock implementation of the VertexBuffer interface and attempt to pass such an implementation to a method of the Device interface. The C++ type checker never sees a problem with that. The attempt leads either to a run-time error or an (uncontrolled) crash.

The need to create multi-sorted abstractions is not rare, unlike your typical Java/C++ book would try to assure you. However, it may be difficult to see this if you are well trained in the Java/C++ way of thinking. I know I didn't really understand this as a major deficiency while I was working mainly in C++. When you are programming in Java or C++ you are used to (even trained to) exposing implementation/extension mechanisms (e.g. double dispatch) that are artificats caused by the lack of support for multi-sorted abstractions.

In ML, one can easily specify multi-sorted abstractions:


signature DIRECT3D =
sig
type device
type vertex_buffer

val newDevice : (* ... *) -> device
val newVertexBuffer : device * (* ... *) -> vertex_buffer
val setStreamSource : device * vertex_buffer * (* ... *) -> unit
(* ... *)
end
structure Direct3D :> DIRECT3D = struct (*...*) end


The above specifies that there are two types device and vertex_buffer. The only way to create values of those types is through the newDevice and newVertexBuffer functions of the module Direct3D.

Vesa Karvonen

Posts: 116
Nickname: vkarvone
Registered: Jun, 2004

Re: Unwritten rules: multi-sorted abstractions Posted: Apr 14, 2006 6:10 AM
Reply to this message Reply
BTW, the ML interface snippet still doesn't capture all the rules of the Direct3D API. Can you spot the problem? (The rule could be expressed at least with either existential types or monads, but it would require a complete restructuring of the program.) However, this doesn't invalidate the point I was making. The Java/C++ type systems simply aren't any good at expressing multi-sorted abstractions, while other type systems (including ML modules) are.

damien morton

Posts: 15
Nickname: dmost
Registered: Jan, 2004

Re: Unwritten rules: multi-sorted abstractions Posted: Apr 14, 2006 6:44 AM
Reply to this message Reply
This reminds me of one huge deficiency in the type systems of Java and C++. Essentially, the Java and C++ type systems, which are based on the traditional single-dispatch ideology of OO, can not easily express multi-sorted abstractions ("multi-sorted" as in "multi-sorted algebra"). In other words, an interface or a class in Java/C++ is only abstract with respect to a single type. However, abstractions are frequently multi-sorted, meaning that you need multiple abstract types ("sorts") to properly express the abstraction. You really can't express such abstractions in Java and C++ properly.

You can easily in C#, for example, by marking the constructor as "internal", which means it is only accessible to the classes within an "assembly".

Isaac Gouy

Posts: 527
Nickname: igouy
Registered: Jul, 2003

an implicit type made explicit Posted: Apr 14, 2006 1:17 PM
Reply to this message Reply
def f(a, b) return a + b; end
Michael Stover wrote "There's an implicit type there - that a and b are addable".

And sometimes we make that explicit, here's a polymorphic fibonacci with explicit constraints (we don't care what type a actually is as-long-as it implements + - one <
fib :: a -> a | + a & - a & one a & < a
fib n
   | n < two   = one
   | otherwise = fib(n-one) + fib(n-two)
   where two = one+one

http://shootout.alioth.debian.org/gp4/benchmark.php?test=recursive&lang=clean&id=3

Isaac Gouy

Posts: 527
Nickname: igouy
Registered: Jul, 2003

dynamic0 dynamic1 dynamic2 ... Posted: Apr 14, 2006 3:04 PM
Reply to this message Reply
> > b) those that think an algorithm that assumes a variable
> > is an integer one time and a string another time is a
> > good thing.
-snip-

Bill Venners wrote
> I think the main benefit of (b)
> is not so much that you can make a variable point to an
> int one minute and a string the next, but that you can
> make a variable point to an object whose class is
> dynamically created at runtime, and easily call any of its
> methods.
>
> Yes, you can do all those kinds of metaprogramming in a
> statically typed language such as Java too...
-snip-
> But it is a lot easier in a dynamic language. Variables in
> dynamic languages can just as easily provide access to an
> object whose class was invented by the running program as
> a class you wrote by hand in source.

But is it a lot easier in a dynamic language just because a variable can reference any object (rather than only being able to reference object's conforming to an interface)?

In PHP a variable can reference any object and yet "It’s not that metaprogramming isn’t possible in PHP, it’s just non-obvious or inconvenient."
http://www.mikenaberezny.com/archives/39

Cleo Saulnier

Posts: 77
Nickname: vorlath
Registered: Dec, 2005

Re: Is Static Typing a Form of Bad Coupling? Posted: Apr 14, 2006 3:41 PM
Reply to this message Reply
Static typing has the same problems as inheritance. We don't often think of changing a primitive type, but it also applies to any compound type. Change it and the entire application changes, oftentimes in very bad ways.

So yeah, there is coupling. Is it bad? I don't think so. But it can be if used incorrectly and 99% of programmers use it incorrectly. Most statically typed languages have inadequate message passing facilities and bad message building facilities. These include C, C++, Java and SmallTalk to name a few. Yet, most software still use these primitive language facilities such as method calling and passing static arguments.

But forget all that for a moment and look at it from a different perspective. Types are currently used a way to define an entity with certain properties. But these are global definitions. We are thinking of these properties from the outside in, when we should be thinking from the inside out.

Here's an example. Let's say you look at a car, you define its properties by shape, size, brand, color, etc... That should be its type. But let's say a dog looks at the car, I'm betting he'll define the car by sound, loundness and smell. An entirely different view from us. At least in importance of properties.

What I'm getting at is that when you create an object or a processing unit, you should define the types as they are required by this processing unit. So if a method can only take integers that are between 0 and 9, then that should be part of its type. But outside of this processing unit, that entity (number) does not need to be between 0 and 9 unless you, the programmer, decides this also fits the outside view of this number.

That's why static typing is having problems. By using dynamic typing, you can have different views of the variables appropriate to the "processing unit" in question. But this is going to the exact opposite extreme where the properties can't even be checked exept explicitely. There is a way in between these two extremes. You convert your types to reflect what the "processing unit" expects to see. When it comes out, you convert it back. The compiler should be able to do most of the work and the "processing unit" in question should provide most of the checks and conversion. That's why templates are becoming popular. They don't convert the data, but they produce code that can accept these different types. What generics lack at the moment is constraints because of what I said before that we're still thinking from the global outside when we should be thinking about each object's point of view and how IT sees the world.

Not everyone sees the world the same. Why we expect all our objects to do so is a rather unique and dangerous idea. Consensus is great, but when there isn't any, that's where the problems you speak of come from.

Achilleas Margaritis

Posts: 674
Nickname: achilleas
Registered: Feb, 2005

Re: New refactoring type Posted: Apr 17, 2006 8:40 AM
Reply to this message Reply

> > The paper is more about why C/C++/Java suck rather than
> > why mandatory type systems are bad. It actually
> presents
> > no evidence for 'significant engineering problems'.
>
> I encounter them. With some refactoring work, I wish I
> could just turn off the typing system for a little while,
> run the program dynamicaly with tests, and then turn it
> back on again. There are times when static typing it gets
> in the way. Don't get me started on what it is like to
> try to get tests into a statically typed system that
> wasn't written with tests in mind. That's a particularly
> grievous engineering problem.
>
> The idea that I want to run with is that typing rules are
> really tests and they should be as flexible as tests. I
> should be able to, in a particular program, say "I don't
> want the Foo class to ever hold a Bar. It can hold
> anything else but not a Bar." I know AspectJ can give you
> that sort of compile time checking. If the type system is
> in the hands of the programmer, it can be another tool to
> put additional constraints on a program and alter them on
> an as needed basis.
>
> One could argue that compile time type systems aren't as
> strong as they could be because they never become program
> specific, they are devised as a tool for all programs in a
> specific language.


But the problems you mention are more due to limitations of the programming language you use rather than due to the nature static types work. For example, the problem of 'Foo can hold anything except a Bar' could easily be encoded in a programming language if the type system allowed the programmer to declare types as algebraic sets (and thus the relationship between types can be expressed with set operations).


If you could run the code dynamically, the tests would give you different information. Tests are about behavior among objects. The type system is about how to name and organize sets of those behaviors. Imagine a Java program with no interfaces. You could probably use 'extract interface' a zillion different ways and still have the same behavior.


That is structural subtyping, mentioned here lots of times by Chris Diggins and others.


Because the program may be correct.


What do you mean "may be correct"? a program is either correct or it is not correct. A program that "may be correct" is also a program that "may be erroneous". And in some time in the future, that error may happen. A programming language should make sure such errors are not possible.


Yes, you can do all those kinds of metaprogramming in a statically typed language such as Java too, either doing static metaprogramming via code generation, or at runtime by using reflection, dynamic proxies, dynamic loading of classes that you use via interfaces they implement, etc. But it is a lot easier in a dynamic language. Variables in dynamic languages can just as easily provide access to an object whose class was invented by the running program as a class you wrote by hand in source.


That is not a factor of how dynamic a language is, but how is the language structured. I can make C++ classes at run-time by putting together opcodes and vtables. Does that make C++ dynamic? nope. Does the static type system of C++ prohibit me from doing so? nope.


That's why static typing is having problems. By using dynamic typing, you can have different views of the variables appropriate to the "processing unit" in question.


Again, the problem you mention is not a problem due to static typing, but a problem of implementation: by using interfaces, a dog can see a car as {smell, loudness, color} and a human can see a car as {brand, type, speed}, for example. In dynamic typing system, the interfaces are there, implicit, but there is no way to ensure the coupling at compile time.

Isaac Gouy

Posts: 527
Nickname: igouy
Registered: Jul, 2003

legal vs correct Posted: Apr 17, 2006 1:01 PM
Reply to this message Reply
> > Because the program may be correct.

Achilleas Margaritis wrote
> What do you mean "may be correct"? a program is either
> correct or it is not correct. A program that "may be
> correct" is also a program that "may be erroneous". And in
> some time in the future, that error may happen. A
> programming language should make sure such errors are not
> possible.

Yes Achilleas, "a program is either correct or it is not correct" but until we know which of those is true, we can only say "the program may be correct" and the program may not be correct.


Achilleas the context was important.
You wrote
> If a program is not legal, then I why should a compiler
> accept it? I think that the concept that "a mandatory type
> system reduces the number of legal programs that can be
> expressed in a language" is a very wrong one.

This program is not legal java but is it correct?
class MyObj {
   public void doStuff(){}
   public static void main(String[] args) {
      Object o = new MyObj();
      o.doStuff();
    }
}
When the type system rejects correct programs it reduces the number of correct programs that can be expressed in the language.

Howard Lovatt

Posts: 321
Nickname: hlovatt
Registered: Mar, 2003

Re: legal vs correct Posted: Apr 17, 2006 8:28 PM
Reply to this message Reply
I agree with the sentiments expressed by by Isaac Gouy in the above post. The example in the post above is easy to fix by changing the declaration of o. Below is a more complelling example of a problem with the type system of Java.
class Base {
  Base inc() {
    // do increment
    return this;
  }
}
 
class Derrived {
  Derrived dec() {
    // do decrement
    return this;
  }
}
 
...
 
Derrived d = new Derrived();
d.inc().dec(); // Error - Base doesn't have a dec

The above can be tackelled to some extent by using generics, but it becomes very complicated and you need to ask if it is worth the trouble. Another alternative is to cast back to a derrived. It would be nice if the compiler automatically added the cast. Another option is self typing, e.g.:
class Base {
  this inc() { // declared as returning this ***and*** only this
    // do increment
    return this;
  }
}
 
class Derrived {
  this dec() {
    // do decrement
    return this;
  }
}
 
...
 
Derrived d = new Derrived();
d.inc().dec(); // OK - d has a dec

These are fairly esoteric cases, so I guess that the designers of Java decided that it wasn't worth the trouble of adding the extra typing mechanisms.

As an aside: one thing from my experiance with both dynamic languages and type inference languages is that the error messages can be very poor. Typically they say method [i]x[/i] dosn't exist. But that error message can occure a long way from the problem, perhaps even inside a third party library. With no indication of where the real problem lies. With type declarations the error is normally found at source.

Achilleas Margaritis

Posts: 674
Nickname: achilleas
Registered: Feb, 2005

Re: legal vs correct Posted: Apr 18, 2006 6:04 AM
Reply to this message Reply

Yes Achilleas, "a program is either correct or it is not correct" but until we know which of those is true, we can only say "the program may be correct" and the program may not be correct.


But it is obvious in many cases that a program is correct, just by looking at it. A static type system helps the compiler do just that. But not having a static type system, you make the compiler blind to things that are obviously wrong.


This program is not legal java but is it correct?

class MyObj {
   public void doStuff(){}
   public static void main(String[] args) {
      Object o = new MyObj();
      o.doStuff();
    }
}


When the type system rejects correct programs it reduces the number of correct programs that can be expressed in the language.


It is not a correct program. By declaring 'o' with type 'Object', you make a request to the compiler to treat 'o' as 'Object'. If you don't want that, as it is obvious from your example, you should have coded this:

   public static void main(String[] args) {
      MyObj o = new MyObj();
      o.doStuff();
    }


If you think that declaring 'MyObj' twice is reduntant (which I agree it is), then you should blame C/C++/Java for it, and not static typing. Your code could have been like this:

   public static void main(String[] args) {
      let o = new MyObj();
      o.doStuff();
    }


and with static type infererence, you wouldn't have to type things twice.

Isaac Gouy

Posts: 527
Nickname: igouy
Registered: Jul, 2003

Re: legal vs correct Posted: Apr 18, 2006 12:54 PM
Reply to this message Reply
Achilleas, I'm just trying to help you understand what people mean when they say the type system reduces the number of correct programs that can be expressed in the language.
class MyObj {
    public void doStuff(){}
    public static void main(String[] args) {
       Object o = new MyObj();
       o.doStuff();
    }
}
> It is not a correct program. By declaring 'o' with type
> 'Object', you make a request to the compiler to treat 'o'
> as 'Object'.

The program is not legal Java.
Just by looking at it we know that the only potential error is failure to allocate a new MyObj. We can see that at runtime o would be an instance of MyObj, and the call to o.doStuff(); would succeed - so in that sense the program is correct.
But the program is not legal Java, so we cannot express this program.

We can express this program in other languages
class MyObj
    def doStuff() end
end
 
o = MyObj.new
o.doStuff

Vesa Karvonen

Posts: 116
Nickname: vkarvone
Registered: Jun, 2004

Re: legal vs correct Posted: Apr 18, 2006 3:59 PM
Reply to this message Reply
I think that your example is not a very good one, because it involves explicitly giving unnecessarily restrictive type ascriptions. You should go for an example that can not be given any type ascription in the static type system whose limitations you are demonstrating. For example, write an expression whose typing requires first-class polymorphism, argue that it is valid (can be given a well defined meaning), and then show that that the expression can not be given a type in SML. For another example, demonstrate that the value restriction of SML rejects many arguably valid programs.

Achilleas Margaritis

Posts: 674
Nickname: achilleas
Registered: Feb, 2005

Re: legal vs correct Posted: Apr 19, 2006 6:49 AM
Reply to this message Reply

Achilleas, I'm just trying to help you understand what people mean when they say the type system reduces the number of correct programs that can be expressed in the language.


Actually, I have understood that. What I have not understood is why these people think their programs are correct, when they are not.


Just by looking at it we know that the only potential error is failure to allocate a new MyObj. We can see that at runtime o would be an instance of MyObj, and the call to o.doStuff(); would succeed - so in that sense the program is correct.


The program is not correct; it's specific instance is, and that correctness is only accidental. If you typed o.doStaff() instead of what you typed, the program would be incorrect, because the method 'doStaff' would not exist in the object 'o'.

'Correctness' is a word that is absolute: something that is correct if it is 100% correct; the little tiniest possibility for error makes something incorrect.

The only reason you typed 'Object' instead of 'MyObj' was your convenience.

The only argument that I personally see as valid from the dynamic camp is that static type systems of mainstream programming languages are not good enough. Having tried something with type inference (ML, for example), I can say that static typing is much more preferrable than dynamic typing.

Most probably it has been said many times before, but catching as many errors as possible before program execution is a desired property.

I would appreciate it if you can post a really good example where dynamic typing is better than static typing.

Isaac Gouy

Posts: 527
Nickname: igouy
Registered: Jul, 2003

Re: legal vs correct Posted: Apr 19, 2006 11:28 AM
Reply to this message Reply
Achilleas Margaritis wrote
> The program is not correct; it's specific instance is, and
> that correctness is only accidental.

Stop right there! In your words, that specific instance of the program is correct.

> If you typed o.doStaff() instead of what you typed, the
> program would be incorrect, because the method 'doStaff'
> would not exist in the object 'o'.

I didn't type o.doStaff() - in your words, that is some other specific instance of the program and just by looking at it we know that it is incorrect.

The answer to "why these people think their programs are correct, when they are not" seems to be that they are talking about what you call a "specific instance of the program" when they say "program" ;-)


> The only reason you typed 'Object' instead of 'MyObj' was
> your convenience.
No, the reason I typed Object was to illustrate the discussion.

-snip-
> Most probably it has been said many times before, but
> catching as many errors as possible before program
> execution is a desired property.

I'm interested in catching errors before program delivery - if that can be done then catching errors before program execution is a luxury.


> I would appreciate it if you can post a really good
> example where dynamic typing is better than static typing.

You'd need to say what you mean by "better" :-)

Isaac Gouy

Posts: 527
Nickname: igouy
Registered: Jul, 2003

some interesting ways to specify types Posted: Apr 23, 2006 1:52 PM
Reply to this message Reply
a workable way to progressively add static typing to a program on an as-needed basis
Pike has "some interesting ways to specify types"
http://pike.ida.liu.se/docs/

mixed This means that the variable can contain any type, or the function return any value.

type1 | type2 This means either type1 or type2

int x; // x is an integer
int|string x; // x is a string or an integer
array(string) x; // x is an array of strings
array x; // x is an array of mixed
mixed x; // x can be any type
string *x; // x is an array of strings
 
// x is a mapping from int to string
mapping(string:int) x;
 
// x implements Stdio.File
Stdio.File x;
 
// x implements Stdio.File
object(Stdio.File) x;
 
// x is a function that takes two integer
// arguments and returns a string
function(int,int:string) x;
 
// x is a function taking any amount of
// integer arguments and returns nothing.
function(int...:void) x;
 
// x is ... complicated
mapping(string:function(string|int...:mapping(string:array(string)))) x;

Flat View: This topic has 74 replies on 5 pages [ « | 2  3  4  5 ]
Topic: Is Static Typing a Form of Bad Coupling? Previous Topic   Next Topic Topic: Python seeks mentors and students for Google Summer of Code


Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2014 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use - Advertise with Us