[M3devel] small array in modula-3?

Darko darko at darko.org
Fri Nov 16 05:54:06 CET 2007


M3 doesn't have class methods or what have you but you can give v a  
method which isn't instance specific which is the same diff and  
doesn't really cost anything. If you read "How M3 Got Its Spots" I  
think the chapter is called they make a reference to this, and not a  
very kind one. I don't think they liked the idea.


On 15/11/2007, at 8:40 PM, Jay wrote:

> But if I don't want to pay for heap allocation, I can't say:
>
> VAR T: v;
>
> v.DoSomething();
>
> Only IMPORT T FROM M;
>
> VAR T: v;
>
> M.DoSomething(v);
>
> Right?
>
> SPIN I think you mean.
> Anyone build it and bring it up? I was long curious but never did..
>
>  - Jay
>
>
>
> > CC: m3devel at elegosoft.com
> > From: darko at darko.org
> > Subject: Re: [M3devel] small array in modula-3?
> > Date: Thu, 15 Nov 2007 20:29:06 -0800
> > To: jay.krell at cornell.edu
> >
> > Not sure what the problem is with modules. If you want to avoid the
> > dot you can name the type something unique then import that type
> > name. You can create an interface with all the nice type names and
> > import all those names in modules by adding an EXPORTS clause too.
> >
> > Personally I think M3, with a couple of extensions, wouldn't need
> > unsafe anything. The unsafe features are there mostly because of
> > legacy interfaces. I forget the name but the folk who wrote an OS in
> > M3 found it very effective with only couple of minor points with
> > regards to interfacing to C code they built on top of, I think  
> one of
> > them was being able to pass NIL to a VAR parameter, which is a  
> common
> > C idiom (and an annoying one for M3 users who then can't use VAR).
> >
> >
> > On 15/11/2007, at 8:08 PM, Jay wrote:
> >
> > > Rodney, thank you, this is interesting.
> > > I definitely don't want to pay for heap allocation for a tiny  
> array.
> > > I don't know about "subarray". It looks like it takes and returns
> > > arrays. It's not a type. I ordered another copy of the Nelson book
> > > so I don't have to find mine.
> > >
> > > Good idea "MakeT" I forgot about that pattern. I'll try it out.
> > >
> > > The record and array I propose are not all that different really.
> > > I just heard of something new. Have you heard of it? "Duck  
> typing".
> > > If it acts/quacks/walks like a duck, it is a duck.
> > > This is in very dynamic languages like Ruby.
> > > You apply object.method and if object defines something named
> > > "method", then it "must" have "the" meaning you intend.
> > > Kind of like how C++ templates "accept as parameters whatever
> > > happens to work".
> > >
> > > Operator overloading is great for strings and "math".
> > >
> > > Maybe I should try to have this language debate from scratch  
> again..?
> > >
> > > I still am conflcted.
> > >
> > > Modules seem overly heavyweight.
> > > I don't want Module1.T, Module2.T, I want T1, T2.
> > >
> > > C++ stack structs with non virtual member functions:
> > > class Rect_t
> > > {
> > > Rect_t() : top(0), left(0), right(0), bottom(0) { }
> > >
> > > int Height() { return bottom - top; }
> > > int Width() { return right - left; }
> > > int top, left, bottom, right;
> > > };
> > >
> > > seems "good".
> > >
> > > And it seems not really all that complicated for the compiler to
> > > flow the static type information around to resolve the functions..
> > >
> > > Rect_t r;
> > > r.Height() => Rect_Height(&r); ..and would be inlined anyway.
> > >
> > > I do find some compelling features in Modula-3. Mainly that it
> > > compiles to native code and has OPTIONAL safety, optional garbage
> > > collection, and that the syntax of modules/interfaces allows fast
> > > compilation -- no longer reparsing the same headers over and over
> > > and over and over.
> > >
> > > Operator overloading btw..have seen "template SafeInt"? It acts
> > > like a primitive integer, but raises exceptions upon overflow.
> > > For this to work very much requires operator overloading.
> > >
> > > A point, of course, is to be able to have user defined types that
> > > can act like the built in types..
> > >
> > > - Jay
> > >
> > >
> > > > Date: Thu, 15 Nov 2007 18:39:18 -0600
> > > > From: rodney.bates at wichita.edu
> > > > To: m3devel at elegosoft.com
> > > > Subject: Re: [M3devel] small array in modula-3?
> > > >
> > > > Jay wrote:
> > > >
> > > > > What is the right way to have a variably sized but always  
> small
> > > array in Modula-3?
> > > > > My array will only ever have 1 or 2 elements.
> > > > > I'd like to always allocate room for 2 elements, and have  
> there
> > > be a size.
> > > > >
> > > > > It seems I have a choice of
> > > > >
> > > > > a) an "open" array
> > > >
> > > > Heap allocated, I presume? If the max size is only 2 elements,
> > > > this is pretty extravagant, as a heap allocated open array will
> > > > have 4 extra behind-the-scenes words of space overhead, plus
> > > > maybe heap fragmentation, and time overhead of allocation,
> > > > collection, and maybe reduced locality of reference.
> > > >
> > > > > b) wrap it up in a record
> > > > >
> > > > > I'd like so have, like:
> > > > >
> > > > > TYPE A = ARRAY [0..1] OF FOO;
> > > > >
> > > > > And be able to say:
> > > > >
> > > > > VAR
> > > > > a : A;
> > > > >
> > > > > ..
> > > > > a.size
> > > > > FOR i := 0 TO a.size DO
> > > > > do something with a[i]
> > > > >
> > > > > It seems I have no option but, like:
> > > > >
> > > > > TYPE A = RECORD
> > > > > a: ARRAY[0..1] OF FOO;
> > > > > size := 1; (* usually of size 1, sometimes 2 *)
> > > > > END
> > > > >
> > > > > and then
> > > > > FOR i := 0 TO a.size DO
> > > > > do something with a.a[i];
> > > > >
> > > > > That is "ok". Not great -- what to call the inner a?
> > > > > But then furthermore, I'd like to construct constants.
> > > > > It seems I am stuck with either the verbose:
> > > > >
> > > > > PROCEDURE F(a:A);
> > > > >
> > > > > F( A { ARRAY[0..1] OF FOO { .. } );
> > > > >
> > > > > OR I have to come up with a name for the embedded array.
> > > > > But of course, its type is really "the same" as the outer  
> type.
> > > >
> > > >
> > > > Ignoring the fact that the types are different linguistically
> > > > (one a record type, the other an array), the types are different
> > > > at a deep semantic level too. The inner array has static
> > > > size, the outer one (call it a "variable array", perhaps)
> > > > has dynamically changeable size, even more easily changed
> > > > after it is created than a heap-allocated open array. This
> > > > is a significant semantic difference, so it also makes program
> > > > design sense to view them as different types.
> > > >
> > > > >
> > > > > To wit:
> > > > >
> > > > > TYPE FooArray = ARRAY[0..1] OF Foo;
> > > > >
> > > > > TYPE FooArray = RECORD
> > > > > a : FooArray;
> > > > > size := 1;
> > > > > END;
> > > > >
> > > > > F( FooArray { FooArray { .. } );
> > > > >
> > > > > But I have to come up with different names.
> > > > >
> > > > > And I don't think I can leave out the name for the  
> constructor,
> > > like:
> > > > >
> > > > > F( FooArray { { .. } );
> > > >
> > > >
> > > > Yes, this is a limitation in Modula-3. Ada allows value  
> constructors
> > > > to omit inner type names in cases like this, and it is
> > > convenient. But
> > > > it also crosses a really major line on complexity of the  
> language
> > > semantics,
> > > > since type analysis information now flows not only upward, but
> > > also downward
> > > > in expression typing. I am mostly content to live with this as
> > > one bit of
> > > > the price of avoiding a horribly over complex language.
> > > >
> > > > Ordinary procedures can do pretty much all of the things done by
> > > exotic
> > > > and complex language stuff like C++ constructors. If you don't
> > > want to write
> > > > the ponderous nested value constructor, write a constructor
> > > procedure and
> > > > call it. As Antony suggested, you can make it accept an open
> > > array formal,
> > > > which then codes just like a simple array value constructor. You
> > > could even
> > > > make it elaborate and general, e.g.:
> > > >
> > > > PROCEDURE MakeF ( Val : ARRAY OF FOO ) : F
> > > >
> > > > = VAR LSize : CARDINAL
> > > > ; VAR LResult : A
> > > >
> > > > ; BEGIN
> > > > LSize := NUMBER ( Val )
> > > > <* ASSERT LSize <= NUMBER ( FooArray ) *>
> > > > ; LResult . size := LSize
> > > > ; SUBARRAY ( LResult . a , 0 , LSize )
> > > > := SUBARRAY ( Val , FIRST ( Val ) , LSize )
> > > > ; RETURN LResult
> > > > END MakeF
> > > >
> > > > Alternatively, since your maximum element count is so small, you
> > > could
> > > > write a constructor procedure that took two formals of type FOO,
> > > with
> > > > at least the second one optional. (This would require a
> > > distinguished
> > > > value of type FOO that would be used to mean "omitted".)
> > > >
> > > > And, of course, if you want to use abstraction, you can put the
> > > types,
> > > > constructor procedures, and various other procedures for
> > > manipulating
> > > > the variable sized array in a module, behind an interface.
> > > >
> > > > An additional limitation of Modula-3 in this regard, is that you
> > > can't
> > > > make the type F opaque, unless you heap allocate it, which we
> > > were trying
> > > > to avoid. Ada would allow you to do this, but it's another
> > > example of
> > > > a convenience with high cost. It forces the equivalent of the
> > > revelation
> > > > to be located in the equivalent of the interface, but makes it
> > > illegal
> > > > to write client code that depends on what the revelation is.
> > > >
> > > > This in turn creates a source code control nightmare in a large
> > > project,
> > > > because now someone who wants to make what is really a purely
> > > internal,
> > > > implementation change, nevertheless has to check out the
> > > interface, and
> > > > if you aren't in denial mode, that means implementers of all the
> > > client
> > > > code have to go to extra trouble to somehow find out that what
> > > appears
> > > > to be an interface change actually doesn't affect them after  
> all.
> > > >
> > > > >
> > > > > Though that might seem nice.
> > > > >
> > > > > Am I understanding everything?
> > > > >
> > > > > Have folks hit this before and there's a set of names that
> > > don't seem too lame
> > > > > that folks use?
> > > > >
> > > > > Also -- language documentation?
> > > > > Nelson's green book is excellent.
> > > > > The stuff in the doc directory is very dry and scientific.
> > > > > The tutorial seems more like a reference. Or maybe I didn't
> > > read it enough.
> > > > > Is there better, in case I need a refresher?
> > > > > I think I got it, via Nelson's book from memory (wonder if I
> > > can find mine..) and the reference,
> > > > > but I don't think anyone could learn from the current online
> > > docs in the source tree.
> > > > >
> > > > > Maybe it's me, some combination of laziness and short  
> attention
> > > span
> > > > > as I age..
> > > > >
> > > > > Btw, C doesn't offer a great solution here, though it offers
> > > leaving out some type names.
> > > > > In C++ I could have both .size and operator[].
> > > > > Modula-3 seems to be missing operator overloading.
> > > > > It's got some builtin stuff, even array assignment and  
> equality
> > > and I think
> > > > > even record assignment and equality, but it is still a bit
> > > limiting.
> > > >
> > > >
> > > > I have raved on this before, but, having had lots of painful
> > > experience with
> > > > user-defined overloading in Ada and C++, I can say with
> > > authority, that it is
> > > > a programming language disaster. It interacts with just about
> > > everything
> > > > else in the language, in very complicated ways, and all it buys
> > > you is saving
> > > > time/energy thinking up distinct names for procedures/functions.
> > > Even this,
> > > > aside from the effects on the language, is a net loss, by the
> > > time you consider
> > > > readability along with writability.
> > > >
> > > > User-defined overloaded operators provide a slight readability
> > > benefit, _if_
> > > > used with great restraint and discipline, something you can rely
> > > on not happening.
> > > > Meanwhile, the language complexity can easily double or worse.
> > > And, with the
> > > > exception of compiler writers and language lawyers who spend
> > > hundreds of hours
> > > > on just this, programmers don't understand the rules, not even
> > > close.
> > > >
> > > > >
> > > > > Also, if I understand things correctly, this has long bothered
> > > me about Modula-3,
> > > > > though I'm more tolerant now -- Modula-3 doesn't seem to allow
> > > for lighter wieght
> > > > > objects. Like, small stack allocated structs with member
> > > functions. You seem to have
> > > > > to chose between heap allocated garbage collected virtual
> > > member functions full
> > > > > featured objects, or featureless dumb structs. It's nice  
> how C+
> > > + allow hybrids --
> > > > > objects don't have to be heap allocated and member functions
> > > don't have be virtual.
> > > > > Or am I missing something?
> > > >
> > > >
> > > > C++'s supposedly lighter weight forms of classes/structs with
> > > their special
> > > > member functions buy nothing that plain records, plain
> > > procedures, and
> > > > interfaces/modules don't already provide, again, at significant
> > > and gratuitous
> > > > language complexity. Except when methods/member functions
> > > actually dispatch
> > > > dynamically, there is nothing that the above won't do, and when
> > > you create a
> > > > class instance as a local variable (i.e., on the stack), it is
> > > necessarily
> > > > not polymorphic, that is, it can't change its "allocated" or
> > > dynamic type
> > > > among various subtypes at runtime. This in turn means it can't
> > > dispatch.
> > > >
> > > > So, just use plain procedures, an interface and a module, and  
> you
> > > will get
> > > > everything a lighter-weight C++ class would give you.
> > > >
> > > >
> > > > >
> > > > > Anyway, I've gotten to accept C a bit more vs. C++ so I can
> > > deal with
> > > > > t: Type;
> > > > > Type_DoSomething(t);
> > > > >
> > > > > in place of:
> > > > > t.DoSomething();
> > > >
> > > >
> > > > Exactly. The special "receiver object" in a true method call has
> > > significant
> > > > semantic differences from an ordinary parameter and introduces
> > > new complexities
> > > > and non-orthogonalities. It has some very valuable uses too.
> > > >
> > > > But to then create degenerate forms of it that still carry a lot
> > > of these
> > > > complexities, but are equivalent in programing power to plain  
> old
> > > > parameters is just bad program design and bad language design.
> > > Objects and
> > > > methods are indeed cool for situations that utilize their
> > > semantic complexity.
> > > > But it's deeply uncool to try to look superficially cool by  
> using an
> > > > inappropriately sophisticated construct when the problem doesn't
> > > justify it.
> > > > Some OO proponents have gone way over the deep end here.
> > > >
> > > > >
> > > > > - Jay
> > > > >
> > > > >
> > > > >
> > >  
> ----------------------------------------------------------------------
> > > --
> > > > > Boo! Scare away worms, viruses and so much more! Try Windows
> > > Live OneCare! Try now!
> > > > <http://onecare.live.com/standard/en-us/purchase/trial.aspx?
> > > s_cid=wl_hotmailnews>
> > > >
> > > >
> > > > --
> > > > -------------------------------------------------------------
> > > > Rodney M. Bates, retired assistant professor
> > > > Dept. of Computer Science, Wichita State University
> > > > Wichita, KS 67260-0083
> > > > 316-978-3922
> > > > rodney.bates at wichita.edu
> > > >
> > > > --
> > > > -------------------------------------------------------------
> > > > Rodney M. Bates, retired assistant professor
> > > > Dept. of Computer Science, Wichita State University
> > > > Wichita, KS 67260-0083
> > > > 316-978-3922
> > > > rodney.bates at wichita.edu
> > >
> > >
> > > Boo! Scare away worms, viruses and so much more! Try Windows Live
> > > OneCare! Try now!
> >
>
>
> Climb to the top of the charts!  Play Star Shuffle:  the word  
> scramble challenge with star power. Play Now!




More information about the M3devel mailing list