Path: utzoo!mnetor!tmsoft!torsqnt!news-server.csri.toronto.edu!bonnie.concordia.ca!uunet!microsoft!marklan From: marklan@microsoft.UUCP (Mark LANGLEY) Newsgroups: comp.lang.eiffel Subject: Continued discussion of object model in Eiffel Keywords: Eiffel c++ object Message-ID: <70548@microsoft.UUCP> Date: 7 Feb 91 22:09:35 GMT Organization: Microsoft Corp., Redmond WA Lines: 95 The protection issue of objects that has been discussed lately (namely, C++ public-protected-private interface, vs Eiffel's idea that you access all your baseclass fields.) gets at another key distinction in the Eiffel object philosophy vs the C++ object philosophy. In Eiffel, when you define a class it is necessary that you be able to get your hands on all the class's fields, because that's the only way you can initialize them! (Well you *could* rename all the features, and get at them that way -- more on this in a sec.) On the other hand, the invariant in C++ is that "C++ will hand you no object before it's initialized." Alternatively, Eiffel hands you objects raw, and just says "Thank you for your support." It's interesting that C++ which has the avowed philosophy of "never add run-time cost" has the more expensive object model. For example, if you inherit a lot of stuff which has constructors, you can find that you spend a lot of time waiting for things to initialize. (Now obviously you can beat the clock a lot of time -- don't declare things you don't want initialized, etc. But the amount of time spent doing unexpected initializations of temporaries, gratuitous copying, initilizing locals, and globals (the latter all at program start-up, whether you will ever need them or not) is non-trivial in big programs.) This extra work that C++ pledges to do for you also leads to another awkward situation: ctor-initialization lists. i.e. When you have : class foo : public base1, public base2, public OhRats { const int OhRats; foo(p1) : base1(10), base2(p1), OhRats(0) { }; }; The constructor initialization list offers three surprises. 1) The order in which things are initialized is controlled by the language, and may bear no resemblence to their order in the list. 2) Your choices on how things get initiliazed are limited. You can't for example say "initialize base1, then call function f, and depending on what it returns initialize base2 with an integer, otherwise initialize it with a null string". 3) you come to grief if you have a baseclass with the same name as a member. Since Eiffel requires that you do your own initialization of baseclasses, I would like to see Eiffel extended to allow invocation of features without having to rename them into the current class; renaming seems awkward, error prone, and misleading. I want to be able to say (yes, I know about the new create syntax -- more on that in a minute) inherit base1; base2 feature create is do current.base1$create(10); -- baseclass '$' feature -- -- whatever other stuff I want to do... -- current.base2$create(20); -- baseclass '$' feature end Now about that new creation syntax: I don't think I like it. The ISE people were good enough to repost the material that they sent out last year sometime on the new create syntax, and I saw a sneak preview in a draft of the manual, but it seems misguided. In the next major release of Eiffel from ISE you will be able to say: local x :someclass; do x! end In the first place, forcing the user to do x! is a cruel hoax. Creation in Eiffel is a two phase process anyway -- the system part initializes and creates an actual object, and then the user fills it in. Decoupling the two phases was a good idea, but why not go all the way? No more void references! always do the system initialization before an object is needed. If you need to tell if an object has been initialized or not, then have a feature "init" or something that gets set to non-zero when the create method runs. (Has eliminating void references been been suggested before? it seems like such an obvious thing...) Version 3's new syntax allows you to call a descendent (not ancestor -- that's what I thought too) function on the current object under construction as follows. x!DescendentFeature!mycreate(10,20); The idea of calling a descendent class is barbaric: It encourages fuzzy reasoning about the type system; It's imprecise and it's error-prone. You can't call a descendent function at any other time in an object's life, why should it be legal at creation time? Mark