Re: How come Ada isn't more popular?



On Wed, 31 Jan 2007 16:16:20 +0100, Markus E Leypold wrote:

"Dmitry A. Kazakov" <mailbox@xxxxxxxxxxxxxxxxx> writes:

On Mon, 29 Jan 2007 16:50:16 +0100, Markus E Leypold wrote:

"Dmitry A. Kazakov" <mailbox@xxxxxxxxxxxxxxxxx> writes:

On Sun, 28 Jan 2007 16:06:48 +0100, Markus E Leypold wrote:

"Dmitry A. Kazakov" <mailbox@xxxxxxxxxxxxxxxxx> writes:

On Sun, 28 Jan 2007 00:24:27 +0100, Markus E Leypold wrote:

Generics is a wrong answer and always was. As well as built-in lists you
are praising is, because what about trees of strings, trees of lists etc.
You cannot build every and each type of containers in.

You missed my point. :-). A language with a Hinldey-Milner type system
has a 'tree of something' type where something can be anything in
every given instance of usage.

You have X of Y. Granted, you can play with Y, but what about X?

I don't understand the question ...

X = tree, Y = something. What about X = something, Y = character.

Example: fixed size strings, unbounded strings, suffix tree. Here the
container (X) varies, the element does not. It is a quite common situation
when you wished to change the containers on the fly.

This situation -- in my experience is much less common. But if you
have it, at the place where you do the manipulation you still need a
common "access protocol" for all thos containers, that is something
like

for K in keys of container; loop

do something with container.item(K);

end loop;

That is what classes are good for (different from parametrized
types). The types of K could well be different here with a
Hindley-Milner type system.

I am not sure what you mean, but it looks quite wrong. (:-)) The iteration
above is based on the interface of an abstract array. Period.

(not every container is array (ordered finite set with a mapping to another
ordered finite set called index)

If I consider your challenge in the context of a function programming
language, the situation you address might not arise as often since
you'd abstract of the iteration as well as probably construct the item
sequence at the location of calling the iteration.

let l = list_of_x ...;;
let t = tree_of_x ...;;


let do_something = ...;; (* single iteration step *)

let fooify_items = fold do_something u ;; (* define the iteration *)

...

... fooify_items l
... fooify_items (Tree.fringe t) (* extract the list of items from t and iterate *)

Efficiency concerns are usually countered (a) by a really good garbage
collection and (b) by lazyiness.

But tree is not an array, it may have an interface of, but I don't see in
your program how that interface works.

As for the functional style I am not impressed. Array interfaces are much
more natural an easier to use. Consider a bunch of tasks concurrently
processing pieces of the same container, exchanging the positions in etc.
But again, it is a stylistic issue which are IMO irrelevant to the type
system.

The point is, the language should not have either X or Y built-in. What

Pursuing this argument further, a language also shouldn't have strings
built in etc. :-).

Yes, sure. The standard library can provide them, but there must be no
magic in.

Here I disgree a bit: Separate syntax is a good thing for the most
common constructs. Else you could as well argue: "A language can
provide constructs for conditional processing or loops, but there must
be no magic" -- meaning that you would want only GOTOs and structured
programming exists only in the mind of the user (I've been programming
like this on micros twenty years ago ...).

And I would insist to do this, if it were possible. But plain gotos don't
work. You need conditionals (arithmetic gotos or stuff like that) and you
need things to handle scopes (loop indices). The result would be a
different language rather than a subset of.

And if I have extra syntax i can as well provide special optimization
rules.

.... or loose some important optimizations.

The user should be able to describe string type in language terms
without loss of either performance or compatibility.

No. I think, strings and lists are so common, that their _semantics_
must be expressible in the core language,

You mean *not* expressible. The only reason for having anything built-in is
because it cannot be expressed in other language terms. So it is postulated
there and expressed in a natural language of the Reference Manual.

questions you (the type system) should answer are like:

Y1 <: Y2 => X of Y1 <: X of Y2
is container of subtypes a subtype?

No. Never.

Which is a catastrophe in my eyes. Consider:

Y1 = Integer;
Y2 = Positive

X = access

Now we have

access Positive is unrelated to access Integer.

What would be of Ada if it were constructed this way?

X1 <: X2 => X1 of Y <: X2 of Y
is sub-container a subtype?

Sub-container is a difficult concept. If it doesn't have binary
methods ... then the answer (off the top of my head) is yes.

How are you going to pass string slices where strings are expected? And the
language I want is such that I could pass an array where a queue is
expected.

The only criterion is
wether the type safety (in the sense given in the Cardelli tutorial)
stays intact. Sometimes I think it is a mistake to mix interface
contracts with type systems: Type systems are too weak to express
contracts, the ad hoc way in which contracts often work, cripple type
systems

Hmm, the language of contracts is not the object language where types live.
In that sense it is decoupled anyway. Therefore the point about type system
is trivially true. Nothing in the object language is strong enough to
express the meta language. You could say same about if-then-else or
integers. If you meant the program semantics/behavior when you talked about
contracts, then that is again true. Nothing can express program semantics
at full. In that sense, yes, LSP was an unrealistic program, which still
does not mean that types are useless. For all I don't see anything useful
proposed instead.

No seriously, I don't consider GC as a problem. Just give me "X of Y." Then
I would take X = access. An do whatever memory collection I want! See?

No?

You have a user-defined access type. You can control everything related to
that type. What else you need to design a collector for such pointers?

There is absolutely no need to have built-in GC, if you have abstract
referential (access) interfaces. Note additional advantage: you can have
different GC's handling objects of same types in the same application!

But there is. Only under very restricted circumstances the necessity
of deallocation can be decided locally. With reference sharing
(representation sharing) between values (think Lisp-like lists -- and
I think you need that for efficience reasons sooner or later -- you're
either back to a "manual" reference counting scheme (inefficient) or
you really need GC.

I don't see how "manual" is different from "implemented by the compiler
vendor." There is no magical GC hardware around... Each GC is reference
counting, only the ways of counting differ.

I notice, that nobody that actually has tried
FP doubts the superiority of the style in general (they are bitching
about efficiency, sometimes, and availability of libraries, mor
often).

It is a very strong argument. FP is even more niche than Ada, for that
matter.

Yes, all languages in question are Turing complete. So you can always
write a Lisp-interpreter and embed it etc. That, though, is not the
point. It does not count wether I can do things "in principle" but how
I can do them and how well the applied abstractions can be seen at a
glance by somebody reading the code later.

Yes, I fully agree, AND I don't want Lisp!

BTW -- another argument _for_ a builtin list syntax.

Hey, Ada already has ()-brackets. Maybe our Unicode fans would propose
special glyphs for )), ))), )))), ))))), )))))) etc. Is it what you mean as
special syntax? (:-))

My feeling is that upward closures destroy the idea of type. However,

So how come that OCaml and Haskell have it? Those languages have a
static type system. Without even RTTI ... :-)

How can anything be statically checked being a result of run-time
computation?

[ I don't consider a hidden argument to popularity, for it is obviously
flawed. Example: Visual Basic. ]

somehow we surely need type objects in some form, for making distributed
systems, for instance (how to marshal non-objects?)

Alice ML does it well. Usually they're just marschalling a cluster of
blocks on the heap, but some languages (Alice ML) are more
sophisticated.

Sending bytes over socket = does it well?

Let types-1 be values, make them values. Then they will need no
declarations, just literals. Soon you will discover some types-2 which
still require declarations. Make them values too. An so on. At some level n
you will have to stop. Now, rename type-n = "type". value, type-k<n =
"value". See? You are where you have started.

I do not understand your argument here. Care to give some example and
I'll try write down how it is down in i.e. OCaml? Perhaps we're
talking on cross purposes too, since I'm not sure I really wanted to
desire the thing you insist I want. :-)

You have the following hierarchy:

values

type-1 = types (sets of values + operations)

type = types?

Either you have a type (IMHO) or types. A still fail to follow you here.

An example of a type is Integer.

type-2 = types of types (sets of types + operations to compose types)
type-3 = types of types of types (...)
...
type-n
...
type-oo

[ value-k = type-k-1 ]

As an example of type-2 you can consider parametrized types. Instances of
them are type-1 (=value-2). Types declared in generic Ada packages are
type-1. All of them considered together ("generic type") is a type-2.
Another example of type-2 in Ada is formal generic type:

generic
type T is range <>;

"range <>" is type-2. The actual T is type-1 (=value-2).

Perhaps the problem is that with parametrized types you try to express a restriction of the kind

List of something where something is in the followin family of types
...

Parametrizing is a mapping:

X : P1 x P2 x...x PN -> T

Here Pi are parameters, T is the set of types (which was denoted as
types-1). Clearly X is not a member of T, X(P1, P2, ..., PN) is. So
parametrized types cannot be types, at least immediately. You need some
equilibristics to bring mappings to or their equivalents into T, as well as
making Pi also members of T. I doubt it were possible in any mathematically
sane way.

With parametrized types in an Hindley-Milner type systems things are
vastly more simple: There is a 'general' 'anything' type and ther are
concrete types. So we have:

- List of anything (really anything)

Which is pretty useless, because "really anything" has no operations =>
cannot be used in ANY way. To start with, anything has neither a "copy
constructor" nor "take pointer to." You cannot have a list of.

But in reality, it is something lesser than anything, and inability to
state what it is, in more or less clear way, is an obvious weakness of the
language.

I deny them as types-2. The huge advantage of pos.1 is that the result is
type-1. The consequence: you can have common values. With type-2 values
(value-1) of different values (type-1) of type-2 are of different types =>
you cannot put them into one container.

We must be talking on cross purposes. I admittedly do not understand
most of the terminology you're using here and certainly cannot apply
it here: Why come, the Hindley-Milner type systems have parametrized
types and don't seem to labor under that kind of problem?

Hmm, I am not mathematician, so it is just a guess. I suppose this is a
part of the problematic Russell-Whitehead type theory and similar address,
while Goedel results prevent us from having "systems of anything." All in
all I think it is quite hopeless.

That should be interface inheritance from concrete types. Yes, Ada misses
that.

No, no, no. Inheritance should never ever decide on on a subtype
relationship. It can't.

It is!

I don't see difference yet. When you inherit only interface, you drop all
the implementation or its parts. This is one issue.

I don't even need a implementation at the start.

Nobody forces you. However, there is a lot of cases when you are given a
concrete type and what to adapt it to something else.

One point is, that
the type fitting into a slot in a functor or as a paramter of a
procedure might well never have been defined explicitely but is a
result of type inference.

Why bother with types if you can infer them? I suppose, because you only
think you can...

Why should anyone bother with inheriting
interfaces from an implementation (espcially if that wouldn't give a
guarantee as far as subtyping compatibility goes).

I don't care about LSP. Neither I consider Liskov's subtyping as a useful
definition of, for the reason you have mentioned. It is never satisfied.

Type inference, if you mean that, is a different one. I doubt that
inference is a right way.

And I don't. I'm actually convinced it is the right way.

I think it is a fundamentally flawed idea. You cannot infer anything
non-trivial. That's the first objection. The second is - even if you could,
then per definition of non-trivial, the reader of the program would be
unable to understand it. Ergo: either you don't need programmers or
inference [or else programs... (:-))]

Since the contract can be broken by new methods anyway, the only thing
that counts from a type safety point of view, is, not to break the
abstraction to the underlying processor / VM, that is, to be able to
call the methods with the right number of parameters and the right
representation of the parameters (at the machine level). So the type
signature is enough.

This is a strange argument. Yes, you cannot verify the semantics, exactly
therefore types come into play. Type only names the behavior, so that it
can be checked formally *without* looking into actual behavior.

But it can't: If B derives from A I have no guarantee, none that B
behaves a an A.

So? If B is declared as a subtype of A, then you, the programmer, are
responsible for B to behave as A. The meaning of this is not the language
business. Does 1 apple behave as 1 orange? Such questions are meaningless.

It's really bothersome that one cannot supply a class X which is
compatible to another class Y by just writing out the right methods.

This is interface inheritance + supertyping + inheritance. It works as
follows:

Really cumbersome. Why not just use the type signatur to decide on the
compatibility?

Because named compatibility is much simpler A=A. As a programmer I don't
want to compare signatures, it adds nothing but complexity. Is 1+1=2? What
is 1, 1, =, +, 2? Does 2 have a signature?

I am not sure what you mean, but when 3 is considered as 1, then
dispatching on bare type tags might become possible.

3? 1? Please elaborate? Is "dispatching on bare type tags" a good or a
bad thing? You lost me there ... (my fault probably).

You can consider type tag as a discriminant so pos.3 is a case of pos.1.

I still don't see the positions -- where is the numbering?

Because you commented them out! Here they are:

"...
1. Constrained subtypes (discriminants)
2. Implementation inheritance without values (type N is new T;)
3. Typed classes (T /= T'Class)
...."

But my dear Dmitry -- What does your sentence "All strings have fixed
length ..." mean than in this context, eh?

That for any given X there exist a function X'Length. We should carefully
distinguish properties of values and types.

And in C this function is?

strlen

--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de
.



Relevant Pages

  • Re: How come Ada isnt more popular?
    ... are praising is, because what about trees of strings, trees of lists etc. ... A language with a Hinldey-Milner type system ... container varies, the element does not. ...
    (comp.lang.ada)
  • Re: add support for other languages
    ... language DLLs or a single DLL with multiple language support, ... Just compile in Unicode ... You can create a hand-edited resource that contains Unicode strings, but you have to do it ... I don't know where is the language support comes into ...
    (microsoft.public.vc.mfc)
  • Re: Obstacles for Tcl/Tk commercial application development ?
    ... language, if variable X is declared as integer it will remain so forever ... Yeah, well, I figured if you fail at some point, you better be able to recover. ... A sane type system would prevent this. ... may fail because some caller is passing something that are not numbers. ...
    (comp.lang.tcl)
  • Re: Two Questions about "strlen", "strcat" and "strcpy"
    ... >>Important is that we have in the standard language a way of using ... > No. zero terminated strings is the whole problem in the first place. ... > programmer to think in terms of implementation and constantly respin ... The standards comitee refuses any change, ...
    (comp.lang.c)
  • Re: GNU gettext
    ... The gettext documentation explains how the keys work. ... translation files, or that you'd need to write a small utility to help ... gettext was desined for plain C, the keys are C strings ... as a developer you have no clue what every language ...
    (microsoft.public.dotnet.languages.csharp)

Loading