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