> "Jeffrey R. Carter" <spam.jrcarter....@spam.acm.org> writes: >> When you see
>> Append (List => List, Element => Element);
>> you don't really know what's being appended to what.
> In a purely generic context, like in the body of > Ada.Containers.Indefinite_Doubply_Linked_LIsts, that is precisely what > you should know.
> What's wrong with that?
First, few people write purely generic code.
Stepanov et al. do. You do. Their admirable work has nevertheless created new words in a new anguage by way of overloading. (Can I suggest the name Techlish ?) Example: Combine "push" and "onto the back end" to have a mathematician from Moscow create the word "push_back" for that. To me, that is 90° off, never mind. (Just a speculation about the origin of push_back. Absolutely no offense intended!) And the concatenation "push" & "_back" is about the linguistic support for the specification of meaning in STL programming there is!
Unfortunately, when you work for some time on one subject, its context becomes familiar to you---but not to others; what is more, and as regards Ada.Containers work, is that the STL and other generic programs revolve all around (a) generic algorithms, (b) a certain machine model. The machine model is necessarily of its own abstract nature. It is the starting point for programming solutions using generic algorithms. Unfortunately, neither the STL nor other libraries offer but internally sensible names. They all force us to switch from our domain to the generic machine. There is a gap in naming mechanisms; everything is lumped together in slang names and most abstract, fluffy terms, full of allusions to the theory behind, but lacking a real mechanism that links the generic composition with the rest of the program. Name wise. We'd need that in order to bridge the gap between the two naming conventions.
There is therefore potential for tons of questions if all a "non-generic" programmer sees is "List" or "Size" in all sorts of places in a program. These words should be endemic among generic library authors, yes. But why anywhere else?
> Op_1 (onto => list, element => object_1); > Op_2 (from => list, element => object_2); > Op_3 (container => list, element => object_3);
> It's much easier if it's always "list => list".
Well, ease as an excuse... I find it much easier to write C++, fast; C++ at some level is much easier and more permissive---easier until there is some odd crash and you look through the large combinatorial array of generic library names(!) in a long diagnostic message...
I think the ease argument will be interesting if it becomes clear what the Op_N stand for, respectively.
The third line is notably not overloading the parameter name "List" and the type name "List".
Cf. valid Eiffel:
local string: STRING do ... -- more uses of string and STRING. Or StrINg.
(Somewhat at odds with the 1-name-rule of that language. I have only a single name space in my brain...) Is this example as confusing than Op (List : List)?
> Nonsense; it is _precisely_ what I want; a list of abstract objects.
> You can't avoid the naming problem by changing the context!
But there should be better ways to resolve the naming problem when changing context. Better than being unspecific, that is: it sure is possible, if redundant, to give a hint to the context.
> Here are the similar definitions from > Ada.Containers.Indefinite_Doubly_Linked_Lists. I hope you won't start > arguing that is a bad abstraction.
No, though it is perhaps notworthy that IIRC the container type's name used to be "Container" in every package in some earlier editions. (I couldn't resist saying some more on names and abstract programming in another reply.)
> Note that it uses _Type for Element!
I think Element_Type was not chosen in order to take sides with the _Type convention.
> How is that better than this:
> package Ada.Containers.Indefinite_Doubly_Linked_Lists is
> type List_Type is tagged private;
> generic > with function "<" (Left, Right : Element_Type) return Boolean is <>; > package Generic_Sorting is
> function Is_Sorted (List : List_Type) return Boolean; > end Generic_Sorting;
There are fewer occurrences of "List" that need disambiguation. But I'll happily leave it to that empirical study of the effects of naming conventions whether other solutions work better or worse.
>> (Rules here: Bits _of_ something, sensor _of_ something, >> these are examples following Tom Moran's comment, if I'm >> not mistaken. Names Sensor and Bits are really quite abstract. >> I would force them to be used for abstract types' names, at best.)
> Yes, if you have a specific context and a specific meaning, then you > should use a specific name. The corollary is that if you have a > generic context, you should use a generic name.
But is the generic context really unspecifiable, i.e., do we have to become vague in our naming? We could state, using names, or adorned names, or ..., that something is useful in many specific cases. This fact is a distinguishing feature.
> [List]
> Who said this was a linked list?
Any programmer with a Lisp background will assume List is :-)
If what matters is the set of operations needed, then is it not possible to specify a frame of reference for this particular meaning of "List"?
> [SAL] "list" tends to imply some access order, meaning there is at > least First, Next, Is_Done. Containers don't have those functions.
This is where conventions can cause problems.
package Ada.Containers.Hashed_Sets is ... function First (Container : Set) return Cursor;
SAL and Ada.Containers differ in their approaches to the same problem, both using the same names connected to incompatible set of operations...
>> generic >> type Less_Equal is new Ordering with private; >> procedure Sort (Container : in out Linked_List);
>> Is anything lost here?
> Yes! You have lost the fact that this is a generic procedure that > doesn't care about the internal structure of the list.
OK. But then, personally, I would have though that (or the abstract linking you have mentioned) would distinguish a List.
> You have also > lost the ability to specify the Order at run-time.
Why? Can't I instantiate with any Ordering type from any block that happens to be visited at run time?
> And "less_equal" implies a mathematical sort. All I really need for a > sort that produces a linear order is "goes_before".
"Goes_Before" a better name, then. Though it corresponds to "Less" only, not "Less_Equal", doesn't it? (I'm desparately looking for how the [= relation is pronounced. Not_After?)
>> I think Dylan made an attempt, at least if one is satified with "car" >> being in a different namespace than "<car>".
> Clearly it's a different name; it's a different lexeme. That's > the same as the _Type convention.
I think this is significant: Many of us care about lexemes much less than digital computers in that we rather correct oddities like spelling errors or <framings> in letter patterns.
>> I'd still not pick essentially the same name for object Car >> and type Car though. Even if Ada had one namespace for types >> and one for other entities. An object is never the same >> as a type, therefore it should be possible to distinguish >> the difference using words.
> Yes! Car is distinguished from Car_Type, but List is not distinguished > from Container. Thank you for agreeing with me :).
OK, to me, Car_Type is only minimally different from Car, and not sufficiently. In particular, the difference carries no meaning in either the objects domain, or in the comain of the value sets of types. (I guess we both would not write procedure Speed_Subprogram (...))
> Actually, I disagree with this statement; overloading types and > objects is fine, since the language does make the distinction clear > from context. In Dylan, I would use "car" and "<car>".
> It sounds like you don't like overloading in the first place. How > about this:
> adding integers is never the same as adding float; it should be > possible to distinguish the difference using words
OCaml does, though with a bit of black dirt only.
> So you don't like "+" (Left, Right : in Integer) and "+" (Left, Right > : in Float)?
> If you do like operator overloading, how is that different from > object/type overloading?
I don't like conventional operators in Ada programs, and more so in C programs: They create a huge set of problems when people think they know what they are doing when writing "+".
> Here are the similar definitions from > Ada.Containers.Indefinite_Doubly_Linked_Lists. I hope you won't start > arguing that is a bad abstraction.
> package Ada.Containers.Indefinite_Doubly_Linked_Lists is
> type List is tagged private;
> generic > with function "<" (Left, Right : Element_Type) return Boolean is <>; > package Generic_Sorting is
> function Is_Sorted (Container : List) return Boolean; > end Generic_Sorting; > end Ada.Containers.Indefinite_Doubly_Linked_Lists;
> Note that it uses _Type for Element!
If anyone cares, that's because we used a form of Stephen's rules for naming these. In this case, we determined that the best name ("Element") should be reserved for the operation, as the operation will likely be used many times, while the formal type name is hardly ever written in client code (just as a name in the instance) -- note this ties into one of the previous threads here. We considered using longer names for the operation like "Get_Element", "Read_Element", etc., but those just made the name longer without adding enough additional information. After all, an important rule is to make names long enough to capture all of the critical information, but no longer (because there is a point where names get too long for readability).
>> I do not mean I'm surprised this convention is working fine with the >> Ada standard packages set, I know there is probably a reason which >> explains why it works in this one case :
> It works for the standard because people are very flexible, and can > work around quirks like this while convincing themselves it's better.
> It would take less effort to use a package if all types followed the > _Type convention. Then more people would have more time to write more > Ada code, and we'd take over the world.
This note gave me a good laugh.
At one point, Matt had use "_Type" in all of the names used in the containers. There are enough people who hate that convention that we ended up changing it. I was surprised by that reaction: Claw uses "_Type" in about 95% of its types (there are few cases where other suffixes made the "_Type" look like pure noise) -- and I don't recall anyone complaining. I would have preferred to continue to use "_Type" in most cases, but it isn't that big of a deal to me.
May be a step to help to go forward : I remember that I oftenly saw, in some Windows API documentations, something which I feel nice : some type declarations were coming with a suggested prefix to be used as a tag indicating the type in the purpose of the Hungarian notation. I'm not thinking about mapping this exact thing, but it make me thing about a similar idea.
This may be cool, to provide a small list of suggested names for concrete instance of generic packages, object instances of a type, derived type name, etc, when applicable. In a whole, the idea to provide naming hints beside declarations, whenever a declaration is subject to later instantiations or later derivations.
This does not solve the question exposed by this topic, but this may be a tool to use in this area.
>> Yes, but reading is also important. The _Type suffix is essentially >> noise when reading; it's only there for the compiler, not the human. >> So you want to read it as few times as possible, as well as write it >> as few times as possible.
> This seems backwards to me. I could use a type name such as X72efY9 for all > the compiler cares. The _Type suffix is most definitely for the human. It > says, "Hey! This is the name of a type so keep that in mind when looking at > this code."
Well, you can read it that way. But the original reason the _Type convention got started (at least, as far as I'm concerned) is to solve the problem of overlapping object and type namespaces.
This is illegal:
procedure (List : in list);
So we have to add noise to either the object or the type, to keep the compiler happy. That's all there is to it.
> In the past I used _Type as a suffix for all of my types. However, there > are times when that doesn't seem to fit. After all the standard types don't > (usually) use a _Type suffix (Character, Integer, Positive, Vector, etc).
The standard is Just Wrong. But we have to live with it.
Georg Bauhaus <rm.dash-bauh...@futureapps.de> writes: > Stephen Leake schrieb:
>> Op_1 (onto => list, element => object_1); >> Op_2 (from => list, element => object_2); >> Op_3 (container => list, element => object_3);
>> It's much easier if it's always "list => list".
> Well, ease as an excuse... I find it much easier to write > C++, fast; C++ at some level is much easier and more > permissive---easier until there is some odd crash > and you look through the large combinatorial array of > generic library names(!) in a long diagnostic message...
I meant easier in all senses; fewer compiler errors, fewer real errors, less development time.
> I think the ease argument will be interesting if it becomes > clear what the Op_N stand for, respectively.
If you start asking about what they stand for, you've missed the point. I should not have to waste time thinking about that; I know they come from the list package, so the type is List_Type, and the parameter name is List. Now I can think about the _other_ parameters.
> Cf. valid Eiffel:
> local > string: STRING > do > ... -- more uses of string and STRING. Or StrINg.
That is the argument both for and against case sensitivity.
On Wed, 04 Nov 2009 19:33:58 -0500, Stephen Leake wrote: > "Peter C. Chapin" <pcc482...@gmail.com> writes:
>> In the past I used _Type as a suffix for all of my types. However, there >> are times when that doesn't seem to fit. After all the standard types don't >> (usually) use a _Type suffix (Character, Integer, Positive, Vector, etc).
> The standard is Just Wrong. But we have to live with it.
Huh, it is not too late to introduce:
package Standard is ... subtype Integer_Type is Integer; end Standard;
But Know what? "subtype" looks awfully wrong! Should not it be "subtype_type"? What about
type_type String_Type is array_type (Integer_Type range <>) of Character_Type;
(:-))
Consider it this way, if _Type is felt appropriate then that is semantically equivalent to types having a separate name space. The latter could be introduced in Ada at any time, being fully backward compatible.
Dmitry A. Kazakov wrote: > Consider it this way, if _Type is felt appropriate then that is > semantically equivalent to types having a separate name space. The latter > could be introduced in Ada at any time, being fully backward compatible.
I'm not sure about the backward compatibility. For one thing, the 'Size attribute may have a different value for a type and for an object of the type. This means that given an object declaration "List : List", where the latter List is a type name, the expression List'Size would be ambiguous and could have a different value for the object List and the type List.
On Thu, 05 Nov 2009 10:48:51 +0200, Niklas Holsti wrote: > Dmitry A. Kazakov wrote:
>> Consider it this way, if _Type is felt appropriate then that is >> semantically equivalent to types having a separate name space. The latter >> could be introduced in Ada at any time, being fully backward compatible.
> I'm not sure about the backward compatibility. For one thing, the 'Size > attribute may have a different value for a type and for an object of the > type. This means that given an object declaration "List : List", where > the latter List is a type name, the expression List'Size would be > ambiguous and could have a different value for the object List and the > type List.
Yes, it is ambiguous, but backward compatible.
Another disadvantage of a separate name space were barring types as first-class objects. I don't know how actual the latter might be.
I have no clear opinion on separate name space for types. Clearly if considered, it should be accompanied with the separate name spaces for labels and package names.
Further, the problem of what to do with
type T_Ptr is access T; type T_Ref is access constant T; type T_Class_Ptr is access T'Class;
> Georg Bauhaus <rm.dash-bauh...@futureapps.de> writes:
>> Stephen Leake schrieb:
>>> Op_1 (onto => list, element => object_1); >>> Op_2 (from => list, element => object_2); >>> Op_3 (container => list, element => object_3); ... > I meant easier in all senses; fewer compiler errors, fewer real > errors, less development time.
What about the time needed to understand the program, or to communicate its meaning, and be it just the outlining of the don't-care parts absent from the naming scheme?
>> I think the ease argument will be interesting if it becomes >> clear what the Op_N stand for, respectively.
> If you start asking about what they stand for, you've missed the > point. I should not have to waste time thinking about that; I know
Here we are... You may know, but I don't; if I am important as a user of your programs, I'd kindly ask you to have the knowledge shine through the names.
> they come from the list package, so the type is List_Type, and the > parameter name is List. Now I can think about the _other_ parameters.
In this case (two things we know: we have a list package and a list type), it is possible instead to give, first,
package List is
type Container is private;
procedure Sort (Elements : in out Container; ...);
and, second, a rule that forces programmers to use a prefix in clients, to make sure the type of "Container" can be seen immediately:
>> local >> string: STRING >> do >> ... -- more uses of string and STRING. Or StrINg.
> That is the argument both for and against case sensitivity.
No, the argument is that a language allowing the same name ("string") to stand for different things, for both objects and types, in the same scope will necessarily add another dimension to the confusion space. Specifically, "string" and "STRING" do not denote the same thing *even* *though* the language Eiffel is case insensitive, like Ada. The lexical overlap of names in separate name spaces plus the case insensitivity add to to the combinatorial explosives in front of the reader. (Of course, in real life forcing good standalone names are simply(*) is countered with "works for me".)
procedure Something (List : in out List; ....), with a namespace for objects and another for types, just places the burden of disambiguation on the reader. Yes, they need to do that sometimes; the author might not forsee the necessity. To me, it does not matter that the author of Something happens to know which is which.
Continuing Dmitry's argument
package List_Package is
type List_Type is private;
function List_Function return List_Type;
end List_Package;
Here, I must choose List_Function because Ada lets me have only one namespace. So I need to add noise, but I (the author) know that the function is just returning a new List, no need to think of a good name, since I know what I am doing... What am I doing?
What would clients look like?
----- (*) "Simply" is a trade mark of Betrand Meyer. :) (There are simply too many occurrences of "simply" in OOSC2 to think otherwise...)
>>> Yes, but reading is also important. The _Type suffix is essentially >>> noise when reading; it's only there for the compiler, not the human. >>> So you want to read it as few times as possible, as well as write it >>> as few times as possible.
>> This seems backwards to me. I could use a type name such as X72efY9 for >> all >> the compiler cares. The _Type suffix is most definitely for the human. It >> says, "Hey! This is the name of a type so keep that in mind when looking >> at >> this code."
> Well, you can read it that way. But the original reason the _Type > convention got started (at least, as far as I'm concerned) is to solve > the problem of overlapping object and type namespaces.
> This is illegal:
> procedure (List : in list);
> So we have to add noise to either the object or the type, to keep the > compiler happy. That's all there is to it.
That is not necessary:
package sdgfkjasf is -- or whayever
type List is ...
procedure jsdfks (List : sdgfkjasf.List);
...
>> In the past I used _Type as a suffix for all of my types. However, there >> are times when that doesn't seem to fit. After all the standard types >> don't >> (usually) use a _Type suffix (Character, Integer, Positive, Vector, etc).
> The standard is Just Wrong. But we have to live with it.
Niklas Holsti <niklas.hol...@tidorum.invalid> writes: > Dmitry A. Kazakov wrote:
>> Consider it this way, if _Type is felt appropriate then that is >> semantically equivalent to types having a separate name space. The latter >> could be introduced in Ada at any time, being fully backward compatible.
> I'm not sure about the backward compatibility. For one thing, the > Size attribute may have a different value for a type and for an object > of the type. This means that given an object declaration "List : > List", where the latter List is a type name, the expression List'Size > would be ambiguous and could have a different value for the object > List and the type List.
The definition of "backward compatible" is "all existing legal programs will still be legal".
This ambiguity does not exist in existing legal programs.
It is a good reason not to have separate name spaces; how would we resolve the ambiguity?
Georg Bauhaus <rm.dash-bauh...@futureapps.de> writes: > Stephen Leake schrieb: >> Georg Bauhaus <rm.dash-bauh...@futureapps.de> writes:
>>> Stephen Leake schrieb:
>>>> Op_1 (onto => list, element => object_1); >>>> Op_2 (from => list, element => object_2); >>>> Op_3 (container => list, element => object_3); > ... >> I meant easier in all senses; fewer compiler errors, fewer real >> errors, less development time.
> What about the time needed to understand the program, > or to communicate its meaning, and be it just the outlining > of the don't-care parts absent from the naming scheme?
I don't understand why you are excluding the naming scheme. Naming conventions are huge gain in understanding.
If I am reading a package that defines an abstract type List_Type, and all primitive operations on List_Type have a parameter named List, then I don't have to try to understand whatever name got used instead of List.
>>> I think the ease argument will be interesting if it becomes >>> clear what the Op_N stand for, respectively.
>> If you start asking about what they stand for, you've missed the >> point. I should not have to waste time thinking about that; I know
> Here we are... You may know, but I don't; if I am important > as a user of your programs, I'd kindly ask you to have the > knowledge shine through the names.
The names of the Op_N, sure. The name of the List parameter is unlikely to add any information.
If there is more than one List paramter (say for Copy, or Splice), then they need better names, of course.
>> they come from the list package, so the type is List_Type, and the >> parameter name is List. Now I can think about the _other_ parameters.
> In this case (two things we know: we have a list package and > a list type), it is possible instead to give, first,
> package List is
> type Container is private;
> procedure Sort (Elements : in out Container; ...);
> and,
Why is this better? It's just a different convention. If you follow it uniformly, it will be just as good as List : in out List_Type.
> second, a rule that forces programmers to use a prefix in clients, > to make sure the type of "Container" can be seen immediately:
What if the problem domain is "any list"? We keep pointing this out, people keep ignoring it.
List.Container is much longer than it needs to be. But that's the "don't use 'use'" argument.
>>> Cf. valid Eiffel:
>>> local >>> string: STRING >>> do >>> ... -- more uses of string and STRING. Or StrINg.
>> That is the argument both for and against case sensitivity.
> No, the argument is that a language allowing the same name > ("string") to stand for different things, for both objects and > types, in the same scope will necessarily add another dimension > to the confusion space. Specifically, "string" and "STRING" do > not denote the same thing *even* *though* the language > Eiffel is case insensitive, like Ada.
That makes no sense. Ah; Eiffel has separate type and object name spaces. So I don't understand the original example; what was the point?
Yes, this is an example of name overloading. Overloading, like any good thing, can be abused.
> The lexical overlap of names in separate name spaces plus the case > insensitivity add to to the combinatorial explosives in front of the > reader. (Of course, in real life forcing good standalone names are > simply(*) is countered with "works for me".)
That is the argument against case insensitivity. I like GNAT's solution to that; issue a warning when an identifier has different casing than the first use.
> procedure Something (List : in out List; ....), with a > namespace for objects and another for types, just places > the burden of disambiguation on the reader.
Yes. But it is a very small burden, pretty much the same as having to read _Type.
The syntax provides all the information necessary; Object : Type.
> Here, I must choose List_Function because Ada lets me have > only one namespace. So I need to add noise, but > I (the author) know that the function is just > returning a new List, no need to think of a good name, > since I know what I am doing... What am I doing?
I don't understand your point. No one has suggested choosing generic names for functions; clearly they need to indicate what the function does. If this function returns a new empty list, I would call it New_Empty_List.
Hmm. I guess you are pointing out that package names, subprogram names, object names, and type names all share the same namespace. Since we feel the need to add noise to types, why don't we feel the same need to add noise to packages and subprograms?
The answer is we just don't :).
There are far fewer package names than other names, and come from the domain, so it's not hard to come up with unique names. Making them plural and everything else singular works pretty well.
Subprogram names tend to be more specific than parameters of an abstract type.
I sometimes have package names that collide with enumeration identifiers:
package Root_Serial_IO is
type Supported_Cards_Type is (Motorola_1, Intel_1, national_semiconductor_42);
type Device_Type is abstract tagged private;
... end Root_Serial_IO;
then I want child packages with the names Root_Serial_IO.Motorola_1 etc; that causes ambiguities, and sometimes ends up being unworkable.
Stephen Leake wrote: > Niklas Holsti <niklas.hol...@tidorum.invalid> writes:
>> Dmitry A. Kazakov wrote:
>>> Consider it this way, if _Type is felt appropriate then that is >>> semantically equivalent to types having a separate name space. The latter >>> could be introduced in Ada at any time, being fully backward compatible. >> I'm not sure about the backward compatibility. For one thing, the >> Size attribute may have a different value for a type and for an object >> of the type. This means that given an object declaration "List : >> List", where the latter List is a type name, the expression List'Size >> would be ambiguous and could have a different value for the object >> List and the type List.
> The definition of "backward compatible" is "all existing legal > programs will still be legal".
Yes, you and Dmitry are right, it would be backward compatible in this sense (which is the common sense). I was thinking that using the same names for types and objects would create problems, for example this ambiguity, and so it would not be "compatible" to take an existing legal program and change type names by, for example, removing "_Type" suffixes.
> This ambiguity does not exist in existing legal programs.
Agreed.
> It is a good reason not to have separate name spaces; how would we > resolve the ambiguity?
Right, that was the problem I had in mind. One way would be to have two different attributes, 'Size for objects and 'Type_Size for types. But that causes backward-compatibility problems unless 'Size is also accepted for types if the name before the 'Size is unambiguously a type name. It may also be difficult for compilers to resolve ambiguous names based on the kind of attribute applied to the name.
On Fri, 06 Nov 2009 04:54:46 -0500, Stephen Leake wrote: > Niklas Holsti <niklas.hol...@tidorum.invalid> writes:
>> Dmitry A. Kazakov wrote:
>>> Consider it this way, if _Type is felt appropriate then that is >>> semantically equivalent to types having a separate name space. The latter >>> could be introduced in Ada at any time, being fully backward compatible.
>> I'm not sure about the backward compatibility. For one thing, the >> Size attribute may have a different value for a type and for an object >> of the type. This means that given an object declaration "List : >> List", where the latter List is a type name, the expression List'Size >> would be ambiguous and could have a different value for the object >> List and the type List.
> The definition of "backward compatible" is "all existing legal > programs will still be legal".
> This ambiguity does not exist in existing legal programs.
And it will not be imposed there by introducing a separation, because presently such names collide.
> It is a good reason not to have separate name spaces; how would we > resolve the ambiguity?
As always by using full names. Note that the argument that some of such names are still ambiguous does not really work, because this is already so in Ada. For example, overloaded subprograms and literals may have indistinguishable full names. So this problem must be addressed anyway. The traditional Ada way would be a qualified expression:
(type'(T))'Size
This returns us back to a more important argument against separate name spaces. Do we really want to have types second-class citizens forever? Are we sure that a type never ever appear in a context of an object? A qualified expression at least suggests that a type is an object.
"Vincent Marciante" <vmarcia...@decilog.com> writes: > "Stephen Leake" <stephen_le...@stephe-leake.org> wrote in message > news:u1vkdrert.fsf@stephe-leake.org... >> This is illegal:
>> procedure (List : in list);
>> So we have to add noise to either the object or the type, to keep the >> compiler happy. That's all there is to it.
> That is not necessary:
> package sdgfkjasf is -- or whayever
> type List is ...
> procedure jsdfks (List : sdgfkjasf.List);
> ...
That's the first time I've seen that suggestion. It's very interesting. The package name has to show up every time the type is paired with an object of the same name. But in other situations, the package name can be left off.
So this ends up being less noise than appending _Type everywhere.
Just to be pedantic, it _is_ adding noise. It's just a different form of noise than _Type.
I'll have to try it in a semi-real project. I've been using _Type for over 15 years, so it will take some effort :).
It's interesting why no one seems to have thought of this before. In general, the way to resolve ambiguities in Ada is to use more of the full name. Somehow that never occured to me in this context.
> "Vincent Marciante" <vmarcia...@decilog.com> writes: > > "Stephen Leake" <stephen_le...@stephe-leake.org> wrote in message > >news:u1vkdrert.fsf@stephe-leake.org... > >> This is illegal:
> >> procedure (List : in list);
> >> So we have to add noise to either the object or the type, to keep the > >> compiler happy. That's all there is to it.
> > That is not necessary:
> > package sdgfkjasf is -- or whayever
> > type List is ...
> > procedure jsdfks (List : sdgfkjasf.List);
> > ...
> That's the first time I've seen that suggestion. It's very > interesting. The package name has to show up every time the type is > paired with an object of the same name. But in other situations, the > package name can be left off.
> So this ends up being less noise than appending _Type everywhere.
> Just to be pedantic, it _is_ adding noise. It's just a different form > of noise than _Type.
> I'll have to try it in a semi-real project. I've been using _Type for > over 15 years, so it will take some effort :).
> It's interesting why no one seems to have thought of this before.
Perhaps because this is not to be applied in a constant manner
> That's the first time I've seen that suggestion.
For objects, this is how task components are matched with acceptor parameters in John Barnes's book (not the exact same thing as object names and type names, for sure, but the prefix is present):
task body W is A: T; begin accept Foo (A: T) do W.A := A; end Foo;
> It's interesting why no one seems to have thought of this before.
My guess is that it has to do with expectations: Many readers will have seen both X and X_Type as type names. Consequently, both forms can denote a type in their expectation. This expectation would have to be unlearned and replaced with yet another expectation, a somewhat idiosyncratic one: that X denotes an object and P.X denotes a type, as you have outlined. At first sight this seems better than _Type, since P.X does not force the mixture of solution words like "X" and "meta names" from the Ada language description like "_Type".
But starting from the first expectation, what really matters is X. How can we map exactly one meaning to exactly one kind of entity presuming it is the direct name that matters?
>> In this case (two things we know: we have a list package and >> a list type), it is possible instead to give, first,
>> package List is
>> type Container is private;
>> procedure Sort (Elements : in out Container; ...);
>> and,
> Why is this better? It's just a different convention. If you follow it > uniformly, it will be just as good as List : in out List_Type.
The convention differs in that none of the identifiers overlap. For me, List and List_Type are just not different enough (the first being a prefix of the second only in a very mechanical sense BTW): I need to combine programs whose authors have followed different naming conventions. In this case I have to take responsibility for disambiguating all occurrences of "List" WRT to their denoting a type or an object.
Yes, if one author chooses to name the package "List" and the type "Container", another chooses type name "List", the situation is equally imperfect. But at least, I feel like the authors have picked names whose differences is more than a dry, formal suffix like "_Type": the difference is in the "domain part" of the type name.
>> second, a rule that forces programmers to use a prefix in clients, >> to make sure the type of "Container" can be seen immediately:
This is what I meant by hinting to the domain. (It seems possible to argue that the word "Any" has a role to play in type names. I haven't seen "any" as part of a type name, though, only as a standalone type name, in Eiffel.) "Any_List" is just explicitly referring to "any list"; I find "list" for "any list" leaves more questions to be asked, given the ubiquitous use of "list". A resolution requires assuming that some convention can decide on the interpretation.
At least, "Any", unlike "_Type" is not from the Ada language vocabulary.
> List.Container is much longer than it needs to be. But that's the > "don't use 'use'" argument.
>>>> Cf. valid Eiffel:
>>>> local >>>> string: STRING >>>> do >>>> ... -- more uses of string and STRING. Or StrINg. > Ah; Eiffel has separate type and object name > spaces. So I don't understand the original example; what was the > point?
In a dozen or so lines of subprogram text, the sequence of characters "String" can refer to two different concepts, in Eiffel, when you have declared string : STRING, an object and a type. The reader, on seeing "String" in the lines following the declaration, is forced to infer from context which concept was meant. Sure, this is possible, not even difficult if you know the language, as every Eiffel compiler demonstrates. But I don't want to assume the role of the compiler just to see what "String" stands for. This is name overloading of two language concepts in the very same inner scope. Even when this if formally just fine, what's the point?
> Yes, this is an example of name overloading. Overloading, like any > good thing, can be abused.
Assuming separate namespaces for objects and types, I can imagine programmers who find "string : STRING" very clever. Or just a good match for some twisted programming trick. Why make cleverness, or the appearance thereof, easy to achieve?
For comparison, imagine a Prolog program that uses Yellow in the parameter list and yellow in the definition. A Prolog fan knows that "Yellow" is not bound AFAIK, since it starts with a capital letter "Y"; "yellow", starting with a small "f", must have been bound somewhere. In a sense, Yellow and yellow live in different namespaces. The image of that definition does confuse me, but I am not sure whether this style is frowned upon in the Prolog community. I hope so. The rule about upper case first letters for Prolog variables has been criticized.
>> procedure Something (List : in out List; ....), with a >> namespace for objects and another for types, just places >> the burden of disambiguation on the reader.
> Yes. But it is a very small burden, pretty much the same as having to > read _Type.
I have to disagree here, for reasons given here and in another post.
> Hmm. I guess you are pointing out that package names, subprogram > names, object names, and type names all share the same namespace. > Since we feel the need to add noise to types, why don't we feel the > same need to add noise to packages and subprograms?
> The answer is we just don't :).
True enough. Yet there are those who feel the need to not add _Type to type names, too, at least when the suffix is used to "free" that same name for objects nearby.
>>> So we have to add noise to either the object or the type, to keep the >>> compiler happy. That's all there is to it.
>> That is not necessary:
>> package sdgfkjasf is -- or whayever
>> type List is ...
>> procedure jsdfks (List : sdgfkjasf.List);
>> ...
> That's the first time I've seen that suggestion.
Or maybe you forgot! The following is part of a old discusion to which you contributed:
Newsgroups: comp.lang.ada From: "Vincent Marciante" <marciant_rem...@li.net> Date: Fri, 5 Oct 2001 15:17:35 -0400 Local: Fri, Oct 5 2001 2:17 pm Subject: Re: on package naming, should the word "_pkg" be part of it?
"Jeffrey Carter" <jeffrey.car...@boeing.com> wrote in message
> John McCabe wrote: > > type Car_Type is > > record > > .... > > end record; > > procedure DoSomething (Car : in out Car_Type); > > could be replaced by: > > type Car is > > record > > .... > > end record; > > procedure DoSomething (The_Car : in out Car); > I recall reading articles about the psychology of understanding programs > (sorry, Robert Dewar, I don't have references for this, either. > Hopefully it's not just random neurons firing in my brain) that stated > that the first few characters of an identifier are the most important in > determining what you're reading. Having identifiers that are identical > for the first few characters requires more time and effort to > understand, and results in more errors in understanding. > Although both _Type and The_ are ways to resolve the type/parameter name > conflict, The_ is worse because it makes the first four characters of > every parameter name the same. > I make the type name reflect what the type contains. For example > type Car_Info ... > procedure P (Car : in Car_Info ... > This is not a popular approach, though, because it requires thought > about every type name. > -- > Jeffrey Carter
> It's very interesting. The package name has to show up every time the type > is > paired with an object of the same name. But in other situations, the > package name can be left off.
> So this ends up being less noise than appending _Type everywhere.
> Just to be pedantic, it _is_ adding noise. It's just a different form > of noise than _Type.
> I'll have to try it in a semi-real project. I've been using _Type for > over 15 years, so it will take some effort :).
> It's interesting why no one seems to have thought of this before. In > general, the way to resolve ambiguities in Ada is to use more of the > full name. Somehow that never occured to me in this context.
Surely these are in different packages? Packages Containers, Lists, and Sequences?
Then it is the package name that gives the domain; that works for me.
> At least, "Any", unlike "_Type" is not from the Ada language > vocabulary.
One reason to use "_Type" is precisely _because_ it means "Ada type"; there's no need to wonder about what it means.
>>>>> Cf. valid Eiffel:
>>>>> local >>>>> string: STRING >>>>> do >>>>> ... -- more uses of string and STRING. Or StrINg. >> Ah; Eiffel has separate type and object name >> spaces. So I don't understand the original example; what was the >> point?
> In a dozen or so lines of subprogram text, the sequence of > characters "String" can refer to two different concepts, in Eiffel, > when you have declared string : STRING, an object and a type.
So the case is not important; why did you introduce it?
In another post, someone said Eiffel required <> around types; is that not true?
> The reader, on seeing "String" in the lines following the > declaration, is forced to infer from context which concept was > meant. Sure, this is possible, not even difficult if you know the > language, as every Eiffel compiler demonstrates.
When designing naming conventions, I always assume you know the language.
In a language like C, sometimes we use conventions that are not strictly necessary, because the syntax is so bad.
I have not used Eiffel, but if I assume the syntax distinguishing type from object is as good as in Ada, then I don't see a problem here.
> But I don't want to assume the role of the compiler just to see what > "String" stands for. This is name overloading of two language > concepts in the very same inner scope. Even when this if formally > just fine, what's the point?
The point, as always in this discussion, is to save time making up separate names for types and objects.
>> Yes, this is an example of name overloading. Overloading, like any >> good thing, can be abused.
> Assuming separate namespaces for objects and types, > I can imagine programmers who find "string : STRING" > very clever. Or just a good match for some twisted programming > trick. Why make cleverness, or the appearance thereof, > easy to achieve?
Good programmers will just find it natural; why introduce twisted programmers into this?
Georg Bauhaus <rm-host.bauh...@maps.futureapps.de> writes: > On 11/6/09 11:26 AM, Stephen Leake wrote: >> "Vincent Marciante"<vmarcia...@decilog.com> writes:
>>> package sdgfkjasf is -- or whayever
>>> type List is ...
>>> procedure jsdfks (List : sdgfkjasf.List);
>>> ...
>> It's interesting why no one seems to have thought of this before.
> My guess is that it has to do with expectations: > Many readers will have seen both X and X_Type as type names. > Consequently, both forms can denote a type in their expectation. > This expectation would have to be unlearned and replaced > with yet another expectation, a somewhat idiosyncratic one: > that X denotes an object and P.X denotes a type, as you > have outlined.
It's only "idiosyncratic" because it's new.
X is still a type name; this is actually a more "normal Ada way" of resolving a name ambiguity.
> At first sight this seems better than _Type, since P.X does not > force the mixture of solution words like "X" and "meta names" from > the Ada language description like "_Type".
> But starting from the first expectation, what really matters > is X. How can we map exactly one meaning to exactly one > kind of entity presuming it is the direct name that matters?
In general, Ada does _not_ require exactly one meaning for one identifier; that's what this discussion is all about.