wg@opal.cs.tu-berlin.de (Wolfgang Grieskamp) (07/28/90)
farrell@batserver.cs.uq.oz.au (Friendless) writes: >jgk@osc.COM (Joe Keane) writes: >>Despite what some people say, i don't think strong typing is such a good deal. >>It catches obvious errors, but doesn't do you any good against less obvious >>bugs. > This is no reason to reject it! But the best thing about strong typing is >the fact that you can take advantage of it when you compile things, by knowing >for example whether they want arguments or not, and you can make assumptions >about what they return when they evaluate, etc. Types are also useful as a >framework for the programmer to think about the roles of various parts of his >program. What is strong typing? Is it just the case that every member of a sum-of-products establish some type and all together another type? Does it requires open type implementations or do you introduce abstract sort names for each member of the sum? Is the domain of a constrained object an anonymous one? Exists any standard paper about strong typing? - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Wolfgang Grieskamp wg@opal.cs.tu-berlin.de tub!tubopal!wg wg%opal@DB0TUI11.BITNET
farrell@batserver.cs.uq.oz.au (Friendless) (07/30/90)
wg@opal.cs.tu-berlin.de (Wolfgang Grieskamp) writes: >farrell@batserver.cs.uq.oz.au (Friendless) writes: >>jgk@osc.COM (Joe Keane) writes: >>>Despite what some people say, i don't think strong typing is such a good deal >>>It catches obvious errors, but doesn't do you any good against less obvious >>>bugs. >What is strong typing? Is it just the case that every member of a >sum-of-products establish some type and all together another type? >Does it requires open type implementations or do you introduce >abstract sort names for each member of the sum? Is the domain of a >constrained object an anonymous one? I didn't have in mind any particular concept of strong typing, other than the idea that you have to be able to determine at compile-time what type things are. Sorry, but I'm not a type-theorist. My particular favourite is Milner polymorphism, because it's easy and it provides exactly the type information which an implementation needs and can use. That is, you need to know the information that Milner typing gives you, and you cannot take advantage of any more. Correct me if I'm wrong, please. John
tom@stl.stc.co.uk (Tom Thomson) (07/31/90)
> I didn't have in mind any particular concept of strong typing, other than >the idea that you have to be able to determine at compile-time what type >things are. Sorry, but I'm not a type-theorist. My particular favourite is >Milner polymorphism, because it's easy and it provides exactly the type >information which an implementation needs and can use. That is, you need to >know the information that Milner typing gives you, and you cannot take >advantage of any more. Correct me if I'm wrong, please. > Why should type checking be restricted to compile time? It is perfectly possible to have strong typing which is done wholely at run-time (any interpreter is going to behave like that). Currently most systems do some type checking at run time: what is a divide-by-zero eroor trap except a type failure indication from the hardware? If you believe that Milner-style type checking is adequate, would you be happy to modify your hardware to not cause this trap but deliver some result of the operation instead? Is "tail" defined on lists or on non-nil lists? If the latter, how do you cope with this in a Milner-style system (pretty clumsily, if at all, I would guess). Personally I would like the type system to ensure, when I reduce a function over a set, that that function is commutative and associative (since the reduction operation is otherwise undefined). I would also like it to check that the unit used in the reduction has the right properties. I can't imagine doing this in a type system that doesn't allow me to make assertions that it is unable to check (actually I can, but doing the operation 2**n times and making sure all the results are the same is not what I want it to do); do Milner style systems give this sort of information? I guess not, but I'm absolutely certain you can take advvantage of it. Tom Thomson [tom @ me.stl.stc.co.uk PS: No, I don't know any language implementations that let me do this, more's the pity.
farrell@batserver.cs.uq.oz.au (Friendless) (08/01/90)
tom@stl.stc.co.uk (Tom Thomson) writes: >Why should type checking be restricted to compile time? Because it makes the implementation faster. I consider this to be enough reason, others may not. In any case, I like to know the types of things when I write the program, and therefore there's no reason the compiler shouldn't. >It is perfectly possible to have strong typing which is done wholely >at run-time (any interpreter is going to behave like that). Not true. An interpreter can do a type checking phase before it runs the program. I know one which does. But this is just splitting hairs. >Currently most systems do some type checking at run time: what is a >divide-by-zero eroor trap except a type failure indication from the hardware? >If you believe that Milner-style type checking is adequate, would you be happy >to modify your hardware to not cause this trap but deliver some result of the >operation instead? >Is "tail" defined on lists or on non-nil lists? If the latter, how do you cope >with this in a Milner-style system (pretty clumsily, if at all, I would guess). Sure, tail can be defined on nil lists. In Miranda, I can say tail [] = error "Tail applied to nil" In this case, error has type list char -> list alpha. It's a hack, but exception handling always is. But I get your point, you can change the type system to be really clever and then not be able to do typing at compile time. But since I am not even one little bit interested in doing run-time type checking, I use Milner types and figure them out at compile-time. Everything which doesn't work is an error rather than a typing failure, and I raise an exception. >Personally I would like the type system to ensure, when I reduce a function >over a set, that that function is commutative and associative (since the >reduction operation is otherwise undefined). I would also like it to check >that the unit used in the reduction has the right properties. I can't imagine >doing this in a type system that doesn't allow me to make assertions that it is >unable to check (actually I can, but doing the operation 2**n times and making >sure all the results are the same is not what I want it to do); do Milner style >systems give this sort of information? I guess not, but I'm absolutely >certain you can take advvantage of it. I have got no idea what you mean by "reduce a function over a set". More information please? John
nick@lfcs.cs.edinburgh.ac.uk (Nick Rothwell) (08/01/90)
In article <3263@stl.stc.co.uk>, tom@stl.stc.co.uk (Tom Thomson) writes: > Why should type checking be restricted to compile time? > It is perfectly possible to have strong typing which is done wholely > at run-time (any interpreter is going to behave like that). No, you can have interpreters which don't do typechecking at all. Our ML system just interprets a form of untyped language calculus. Why is typechecking an issue connected to interpretation? > Currently most systems do some type checking at run time: what is a > divide-by-zero eroor trap except a type failure indication from the hardware? 0 is an integer, just like 17 is. Milner-style typechecking is structural, so it knows about, say, integers, but not about positive integers, primes, and non-structural entities of this kind. -- Nick Rothwell, Laboratory for Foundations of Computer Science, Edinburgh. nick@lfcs.ed.ac.uk <Atlantic Ocean>!mcsun!ukc!lfcs!nick ~ ~~ ~~ ~~ ~~ Hey, son, get that DeLorean off the track! And ~~ ~~ ~~ ~~ ~ what have you done with all my lovely harpsichords?
dnt@lfcs.ed.ac.uk (David N Turner) (08/01/90)
In article <3263@stl.stc.co.uk>, tom@stl.stc.co.uk (Tom Thomson) writes: > ... > Currently most systems do some type checking at run time: what is a > divide-by-zero error trap except a type failure indication from the hardware? > If you believe that Milner-style type checking is adequate, would you be happy > to modify your hardware to not cause this trap but deliver some result of the > operation instead? > > Is "tail" defined on lists or on non-nil lists? If the latter, how do you cope > with this in a Milner-style system (pretty clumsily, if at all, I would guess). > ... > Tom Thomson [tom @ me.stl.stc.co.uk > ... I think you are confusing type checking, which gives information about the type of a value at run time (shockingly enough), and a system which gives information about the actual value returned at run time. With reference to your "tail" example, Milner-style type checking will guarantee that you never apply "tail" to anything other than a list. It does not say anything, however, about whether "tail" is applied to a nil list. The kind of information you are asking for is slightly more ambitious I think, bearing in mind that we cannot write a program to determine whether a function halts or not. Dave.
brendan@batserver.cs.uq.oz.au (Brendan Mahony) (08/04/90)
I think we need some definitions of terminaology. The word type is being badly abused in this discussion. The two sides essentially coming at it with two different definitions. How about we adopt the algebrist's terminology and go from there. Type: What you write after the colon in a variable declaration. This can be any set valued expression. Sort: The essential structure of an object. Essentially the largest homogeneous set containing the object. Essentially a cludge invented to make decidable "typing" algorithms. VERY context dependant. For example, whether 3 is INTEGER or REAL or whatever, depends on what you have decided as your basic sorts: an abitrary decision. Now having sorting information is simply not enough to ensure that partial functions will always be safely applied. You need to do some sort of exception handling. The question is whether the exception handling is done within the functional paradigm or whether you invent side-effects to handle such problems. To my mind the functional paradigm is either superior or it is not. If you have to introduce side-effects to handle anything then you might as well be programming in C from the start. -- Brendan Mahony | brendan@batserver.cs.uq.oz Department of Computer Science | heretic: someone who disgrees with you University of Queensland | about something neither of you knows Australia | anything about.
tom@nw.stl.stc.co.uk (Tom Thomson) (08/06/90)
In article <5448@castle.ed.ac.uk> nick@lfcs.ed.ac.uk (Nick Rothwell) writes: >0 is an integer, just like 17 is. Milner-style typechecking is structural, >so it knows about, say, integers, but not about positive integers, primes, >and non-structural entities of this kind. > I think this misses the point completely. The reason for introducing zero-division as an example was precisely to point that Milner-style type checking doesn't cover this case - - in fact any type checking system that insists on operating at compile time and not at run time (while leaving it possible to write a reasonable range of programs) will fail to cover this case. Also, what does structural mean in this context? In terms of structural types, I can easily define positive integers as a type distinct from natural numbers including zero. I have never come across a functional language that would stop me doing this. I think it might be useful to think about why we have type systems (to limit the damage when we apply a function to arguments outside its domain) rather than what a particular type system (or class of type systems) can do. Tom Thomson [tom@nw.stl.stc.co.uk
tom@nw.stl.stc.co.uk (Tom Thomson) (08/06/90)
In article <5450@castle.ed.ac.uk> dnt@lfcs.ed.ac.uk (David N Turner) writes: >I think you are confusing type checking, which gives information about the type >of a value at run time (shockingly enough), and a system which gives >information >about the actual value returned at run time. With reference to your >"tail" example, >Milner-style type checking will guarantee that you never apply "tail" to >anything >other than a list. It does not say anything, however, about whether >"tail" is applied >to a nil list. > >The kind of information you are asking for is slightly more ambitious I think, >bearing in mind that we cannot write a program to determine whether a function >halts or not. > >Dave. No, I'm not confused, you are. Even if I restrict myself to compile-time type checking, there doesn't appear to be any reason to restrict myself to type checking which is guaranteed to terminate (since I can probably write programs which won't terminate at run time, why should I insist they terminate at compile time?) - but maybe that wasn't your point? When I'm trying to point out deficiencies in compile-time-only type checking in general, you don't advance the discussion any by pointing out that one particular style of compile-time type system has the very deficiencies I'm drawing attention to - - at least not if you think you are disagreeing with me! Type checking is about one very simple semantic issue: is the argument I'm using in the domain of the function I'm applying (in the sense of it making sense to try to apply the function; the result may be bottom, or not, that's irrelevant, we just want to be sure that we're not asking our program to eat a chair or sit on a cream bun). We need to look at how well the type system characterises the domains of the functions we want to use. Then we need to look at how well the functions we want to use map these domains onto each-other. This will throw up a variety of problems, some of which can be handled by a Milner type system and some of which cannot, and some of which are best handled during transformation from one representation (ML, say) to another (PDP8 machine code say) and some of which are best handled during evaluation of the program (ok, so the distinction between evaluation and transformation is theoretically unsound, because evaluation is simply transformation of representations of values; despite that I'll stick with it, because I have to deal with practical engineering). I think your article is trying to claim that the two occurences of "some of which" in the preceding paragraph refer to the same subset of the problems at issue. Where's your evidence for that? If you weren't claiming that, what DID you mean to say? Tom Thomson [tom@nw.stl.stc.co.uk
tom@nw.stl.stc.co.uk (Tom Thomson) (08/06/90)
In article <4461@uqcspe.cs.uq.oz.au> farrell@batserver.cs.uq.oz.au writes: >tom@stl.stc.co.uk (Tom Thomson) writes: >>Why should type checking be restricted to compile time? > > Because it makes the implementation faster. I consider this to be enough >reason, others may not. In any case, I like to know the types of things when >I write the program, and therefore there's no reason the compiler shouldn't. Yes, we should tell the compiler as much as possible and let it do as much work as possible at compile time. After all, we are going to run most programs more often than we compile them. But this doesn't mean that we should not allow our machine to check for inappropriate arguments to functions at run time - - no compiler is that clever (maybe some programmers are, but then presumably they don't need a compile-time type checker either? I know I'm not that clever). > Sure, tail can be defined on nil lists. In Miranda, I can say > >tail [] = error "Tail applied to nil" > >In this case, error has type list char -> list alpha. It's a hack, but >exception handling always is. But I get your point, you can change the type >system to be really clever and then not be able to do typing at compile time. >But since I am not even one little bit interested in doing run-time type >checking, I use Milner types and figure them out at compile-time. Everything >which doesn't work is an error rather than a typing failure, and I raise an >exception. > I think we agree on everything except terminology. Certain errors I would call type errors, and expect "the system" to detect for me and raise an exception; you've chosen not to call them type errors. I would, however, point that type resolution (and in particular resolution of overloading) can occur at run time (as well as error detection); most object-oriented languages seem to have this capability; when one wants a module capability, so that one ends up with different implementations of the same abstract type and transfer functions to convert between them, some run-time resolution seems inevitable. >>Personally I would like the type system to ensure, when I reduce a function >>over a set, that that function is commutative and associative (since the >>reduction operation is otherwise undefined). I would also like it to check >>that the unit used in the reduction has the right properties. I can't imagine > > I have got no idea what you mean by "reduce a function over a set". More >information please? > This is pretty straightforward. If I have a set of numbers, I can talk about their sum and their product; these two things are described by a "reduction" function: one reduces binary addition (or binary nultiplication) over the set with respect to an unit value of zero (or one). It's not possible to talk about the difference or quotient of a set, because subtraction and division do not have the right properties. Think of it as starting from a function on lists: reduce :: ((alpha * beta) -> beta) * beta * list alpha -> beta; reduce f u (cons a l) = reduce f (f a u) l; reduce f u nil = u; Then impose the requirement that it's meaningful for sets, rather than just for lists: ie you have to get the same result for the same set of list elements, regardless of the order they occur in. You can see how this requirement to be relevant to sets imposes restrictions on the function "f" in the above definition; and today's type systems do not allow me to specify these restrictions. Tom Thomson [tom@nw.stl.stc.co.uk
dnt@lfcs.ed.ac.uk (David N Turner) (08/06/90)
In article <3283@stl.stc.co.uk>, tom@nw.stl.stc.co.uk (Tom Thomson) writes: > ... > Even if I restrict myself to compile-time type checking, there doesn't > appear to be any reason to restrict myself to type checking which is > guaranteed to terminate (since I can probably write programs which won't > terminate at run time, why should I insist they terminate at compile time?) > - but maybe that wasn't your point? > ... That was roughly my point (I think :-). I think the problem with your idea for enhanced type checking is that it puts type checking algorithms into a completely different ballpark. There are enough problems with the time complexity etc. of current type checkers (which don't even scratch the surface of what you are suggesting). I accept your point that since we can write programs that don't terminate then perhaps we shouldn't worry too much about non-termination during compilation. However, when you say "why should I insist THEY terminate at compile time". Your argument relies on the fact that the only programs which don't terminate at compile time are the ones which don't terminate at run time. Even if you didn't mean the "THEY" to have such emphasis then I think there is still a point to be made : the kind of type checking algorithm you suggest, which is far more powerful than, for instance, Milner-style type checking is surely quite likely to fail to terminate (before you get fed up waiting :-) for valid programs as well as programs which would not terminate anyway. Hence, you cannot ignore problems with non-termination and time complexity. Dave.
sakkinen@tukki.jyu.fi (Markku Sakkinen) (08/08/90)
Note2: Third trial to post! Note1: This is the second posting of an article that apparently disappeared while the news software was out of order here for three days. Sorry if somebody receives it twice. In article <3283@stl.stc.co.uk> "Tom Thomson" <tom@stl.stc.co.uk> writes (rather as a side issue in the posting): > ... >Even if I restrict myself to compile-time type checking, there doesn't >appear to be any reason to restrict myself to type checking which is >guaranteed to terminate (since I can probably write programs which won't >terminate at run time, why should I insist they terminate at compile time?) > ... Run-time termination (i.e. the termination of _your_ programme) and compile-time termination (i.e. the termination of the _compiler_ you use) are two totally independent things. Well, not totally: if the compilation never terminates, there will never _be_ an executable form of your programme to run. I estimate that 99.99999% of all programmers would consider a compiler badly broken if it did not terminate, or even if its time requirement seemed exponential w.r.t. source code size. And very few programmers would accept to use a _language_ for which it is impossible to build a terminating compiler; even though many programmers today seem to delight in horrible languages like C. (I am a complete outsider in this group. Perhaps non-imperative programmers have more patience than we others.) Markku Sakkinen Department of Computer Science University of Jyvaskyla (a's with umlauts) Seminaarinkatu 15 SF-40100 Jyvaskyla (umlauts again) Finland SAKKINEN@FINJYU.bitnet (alternative network address)
brendan@batserver.cs.uq.oz.au (Brendan Mahony) (08/09/90)
tom@nw.stl.stc.co.uk (Tom Thomson) writes:
->This is pretty straightforward.
->If I have a set of numbers, I can talk about their sum and their product;
->these two things are described by a "reduction" function: one reduces
->binary addition (or binary nultiplication) over the set with respect to
->an unit value of zero (or one). It's not possible to talk about the
->difference or quotient of a set, because subtraction and division do not
->have the right properties.
->Think of it as starting from a function on lists:
->reduce :: ((alpha * beta) -> beta) * beta * list alpha -> beta;
-> reduce f u (cons a l) = reduce f (f a u) l;
-> reduce f u nil = u;
->Then impose the requirement that it's meaningful for sets, rather than just
->for lists: ie you have to get the same result for the same set of list
->elements, regardless of the order they occur in.
->You can see how this requirement to be relevant to sets imposes restrictions
->on the function "f" in the above definition; and today's type systems do
->not allow me to specify these restrictions.
Presumably, the requirement on f is that (f,u,T) form an abelian group.
This certainly cannot be established either at compile or run-time. It
must be established during the specification and refinement phase, since
it will be undecidable for non-finite sets T, and essentially be
somewhat unwieldy for largish sets, say of size 10 and above. I think,
in part, you are pointing out a problem with the exclusive use of
executable notations.
The typing problem occuring here lies in the fact that "reduce" will
happily go about its business regardless of the nature of the "f" and
"u" passed to it. The user may never realise that the answers being
produced are complete garbage. This example shows that the original
problem put forward goes far beyond the idiosyncracies of lazy
evaluation.
In fact it helps make it clear that the original problem was
due to a failure of type security not to the method of evaluation used.
The function in question was being used incorrectly. It is the job of
the programmer to ensure that an overall product cannot be used
incorrectly (i.e. it must at least make it clear that it is producing
garbage), and hence that all internal functions are always used correctly.
The primary tool available for ensuring this is the programmers
intellect. Compile time and run-time checks can help in discovering some
incorrect uses of functions, but as we have seen the general problem is
theoretically beyond their capacity. The only way of having reasonable
confidence that all functions will always be used correctly is to
produce rigorous logical proofs that this is the case. Lambda calculus
is not an appropriate vehicle for producing such proofs, though its
cousin natural deduction is a good candidate for such a vehicle.
Far too little effort is being made by the fp community to deal with
this problem.
--
Brendan Mahony | brendan@batserver.cs.uq.oz
Department of Computer Science | heretic: someone who disgrees with you
University of Queensland | about something neither of you knows
Australia | anything about.
JWC@IDA.LiU.SE (Jonas Wallgren) (08/10/90)
In article <5448@castle.ed.ac.uk> nick@lfcs.ed.ac.uk (Nick Rothwell) writes: >In article <3263@stl.stc.co.uk>, tom@stl.stc.co.uk (Tom Thomson) writes: >> Currently most systems do some type checking at run time: what is a >> divide-by-zero eroor trap except a type failure indication from the hardware >0 is an integer, just like 17 is. Milner-style typechecking is structural, >so it knows about, say, integers, but not about positive integers, primes, >and non-structural entities of this kind. Then perhaps some appropriate questions are: What is a type? What are types used for? Should the type of an object exactly describe its possible values (Tom T), or should types be coarse, well-known approximations (Nick R), such as integers, thus making reasoning about the program simpler? Maybe there are as many answers to these questions as there are programmers and computer scientists...? ------------------------------------------------------------------------------- Jonas Wallgren | JWC@IDA.LiU.SE Department of Computer and Information Science | Linkoping University |------------------------------- SE-581 83 Linkoping | Sweden |(\x.xx)(\x.x):(forall a.(a->a)) -------------------------------------------------------------------------------
des@frogland.inmos.co.uk (David Shepherd) (08/21/90)
In article <1990Aug17.124142.9332@tukki.jyu.fi>, sakkinen@tukki.jyu.fi (Markku Sakkinen) writes: |> I estimate that 99.99999% of all programmers would consider |> a compiler badly broken if it did not terminate, or even if its |> time requirement seemed exponential w.r.t. source code size. |> And very few programmers would accept to use a _language_ for which |> it is impossible to build a terminating compiler; even though |> many programmers today seem to delight in horrible languages like C. try using SunOS 4.0 cc on a Sparc with -04 (or even -02 sometimes) on some files .... I've heard of one the went 24hrs and still counting :-) -------------------------------------------------------------------------- david shepherd: des@inmos.co.uk or des@inmos.com tel: 0454-616616 x 529 inmos ltd, 1000 aztec west, almondsbury, bristol, bs12 4sq