From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-0.3 required=5.0 tests=BAYES_00, REPLYTO_WITHOUT_TO_CC autolearn=no autolearn_force=no version=3.4.4 X-Google-Thread: 103376,21960280f1d61e84 X-Google-Attributes: gid103376,public X-Google-Language: ENGLISH,ASCII-7-bit Path: g2news2.google.com!news4.google.com!border1.nntp.dca.giganews.com!nntp.giganews.com!newsfeed00.sul.t-online.de!t-online.de!news.karotte.org!news2.arglkargh.de!noris.net!newsfeed.arcor.de!newsspool4.arcor-online.net!news.arcor.de.POSTED!not-for-mail From: "Dmitry A. Kazakov" Subject: Re: How come Ada isn't more popular? Newsgroups: comp.lang.ada User-Agent: 40tude_Dialog/2.0.15.1 MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Reply-To: mailbox@dmitry-kazakov.de Organization: cbb software GmbH References: <1169531612.200010.153120@38g2000cwa.googlegroups.com> <1mahvxskejxe1$.tx7bjdqyo2oj$.dlg@40tude.net> <2tfy9vgph3.fsf@hod.lan.m-e-leypold.de> <1g7m33bys8v4p.6p9cpsh3k031$.dlg@40tude.net> <14hm72xd3b0bq$.axktv523vay8$.dlg@40tude.net> <4zwt33xm4b.fsf@hod.lan.m-e-leypold.de> Date: Thu, 1 Feb 2007 15:22:02 +0100 Message-ID: <1j7neot6h1udi$.14vp2aos6z9l8.dlg@40tude.net> NNTP-Posting-Date: 01 Feb 2007 15:22:02 CET NNTP-Posting-Host: 9566bdaa.newsspool3.arcor-online.net X-Trace: DXC=U<^>IGKXa;]<<0iRN7DLEQMcF=Q^Z^V3X4Fo<]lROoRQgUcjd<3m<;R?SCUAm0T`o][6LHn;2LCV^7enW;^6ZC`TIXm65S@:3>_DZRHY^G=ES[ X-Complaints-To: usenet-abuse@arcor.de Xref: g2news2.google.com comp.lang.ada:8816 Date: 2007-02-01T15:22:02+01:00 List-Id: On Wed, 31 Jan 2007 16:16:20 +0100, Markus E Leypold wrote: > "Dmitry A. Kazakov" writes: > >> On Mon, 29 Jan 2007 16:50:16 +0100, Markus E Leypold wrote: >> >>> "Dmitry A. Kazakov" writes: >>> >>>> On Sun, 28 Jan 2007 16:06:48 +0100, Markus E Leypold wrote: >>>> >>>>> "Dmitry A. Kazakov" 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>>> "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