<html>
<head>
<style><!--
.hmmessage P
{
margin:0px;
padding:0px
}
body.hmmessage
{
font-size: 12pt;
font-family:Calibri
}
--></style></head>
<body class='hmmessage'><div dir='ltr'><pre style="margin-bottom:14pt">  > If fact, if you are accustomed to thinking in type-safe terms</pre><br>I do think in fairly type-terms.<br>In C++ I know to use templates, for example.<br>There is a matter of lifetime-safety though.<br>I understand that they are related -- if I get the lifetime wrong, then I end up with the type wrong, e.g. using freed-and-possibly-reallocated memory as if it was what it used to be and what I thought it still is.<br><br><br>Consider C++ code like this, where I want to do some things<br>"the same" to a bunch of variables, and some things "specific".<br><br><br>struct Person_t { const char* name; };<br><br>void F()<br>{<br>Person_t jay {"jay"};<br>Person_t randy = {"randy"};<br>Person_t tony = {"tony"};<br><br>// print all their names<br>  Person_t* people[] = {&jay, &randy, &tony};  <br>  for (i = 0; i < sizeof(people) / sizeof(people[0]; ++i)  <br>    printf("%s\n", people[i]->name);  <br><br>   DoSomethingSpecificToJay(&jay);  <br>   DoSomethingSpecificToRandy(&randy);  <br>  
DoSomethingSpecificToTony(&tony);  <br>

<br>}<br><br>I do NOT want to do this:<br><br>void F()<br>
{<br>
  Person_t people[3] = {{"jay"}, {"randy"}, {"tony"}};  <br>
<br><br> // print all their names <br>

  for (i = 0; i < sizeof(people) / sizeof(people[0]; ++i)   <br>
     printf("%s\n", people[i].name);   <br>
<br>
   DoSomethingSpecificToJay(&people[0]);  <br>
   DoSomethingSpecificToRandy(&people[1]);   <br>
  
DoSomethingSpecificToTony(&people[2]);   <br>


<br> } <br>
<br> I understand there is: <br>enum People { jay, randy, tony };<br>...<br>   DoSomethingSpecificToJay(&people[jay]);  <br>

   DoSomethingSpecificToRandy(&people[randy]);  <br>

  
DoSomethingSpecificToTony(&people[tony]);  <br>



...<br><br><br> but I'm still not thrilled about that. <br><br>I ended up without anything "specific" except initialization..so no<br>really need to hang a name/variable on the data, and the<br>initialization is fairly specific, so the resulting code is merely:<br><br><br>    EVAL Type_Init(NEW(Integer_t, cg_type := Target.Integer.cg_type, typeid := UID_INTEGER));<br>    EVAL Type_Init(NEW(Integer_t, cg_type := Target.Word.cg_type, typeid := UID_WORD));<br>    EVAL Type_Init(NEW(Integer_t, cg_type := Target.Int64.cg_type, typeid := UID_LONGINT));<br>    EVAL Type_Init(NEW(Integer_t, cg_type := Target.Word64.cg_type, typeid := UID_LONGWORD));<br><br>    EVAL Type_Init(NEW(Float_t, cg_type := Target.Real.cg_type, typeid := UID_REEL));<br>    EVAL Type_Init(NEW(Float_t, cg_type := Target.Longreal.cg_type, typeid := UID_LREEL));<br>    EVAL Type_Init(NEW(Float_t, cg_type := Target.Extended.cg_type, typeid := UID_XREEL));<br><br>    EVAL Type_Init(NEW(Enum_t, cg_type := Target.Word8.cg_type, typeid := UID_BOOLEAN, max := 1));<br>    EVAL Type_Init(NEW(Enum_t, cg_type := Target.Word8.cg_type, typeid := UID_CHAR, max := 16_FF));<br>    EVAL Type_Init(NEW(Enum_t, cg_type := Target.Word16.cg_type, typeid := UID_WIDECHAR, max := 16_FFFF));<br><br>    EVAL Type_Init(NEW(Subrange_t, cg_type := Target.Integer.cg_type, typeid := UID_RANGE_0_31, min := 0, max := 31));<br>    EVAL Type_Init(NEW(Subrange_t, cg_type := Target.Integer.cg_type, typeid := UID_RANGE_0_63, min := 0, max := 31));<br><br> ... <br><br>you can see it in m3back/src/M3C.m3 (which tangentially I think strikes at possible problems<br>in the m3cg interface...these types need to be defined via function calls into the backend,<br>not hardcoded..and even if they are...the order of types arriving at the backend isn't always<br>ideal..types maybe come in before they are referenced..maybe that is unavoidable due to loops...<br>I suspect I need to put in the multiple passes like I did in parse.c...we'll see...)<br><br><br> - Jay<br><br><br><div><div id="SkyDrivePlaceholder"></div>> From: jay.krell@cornell.edu<br>> Date: Wed, 15 Aug 2012 12:56:09 -0400<br>> To: hosking@cs.purdue.edu<br>> CC: m3devel@elegosoft.com; jay.krell@cornell.edu<br>> Subject: Re: [M3devel] reference to globals in globals?<br>> <br>> I restructured the code but it still bothers me. Getting the levels of indirection correct is checked for you in C/C++ as '&' returns a stronger type than 'ADR'.<br>> I didn't want the array only because then I could only access the data more verbosely/slowly via the array.  More later, maybe.<br>> <br>>  - Jay (briefly/pocket-sized-computer-aka-phone)<br>> <br>> On Aug 15, 2012, at 12:11 PM, Tony Hosking <hosking@cs.purdue.edu> wrote:<br>> <br>> > Jay,<br>> > <br>> > Any time you want to pass a reference to a local/global as a parameter you can use VAR/READONLY parameter mode.<br>> > <br>> > I don’t know enough about your use-case to understand what you are trying to do.<br>> > <br>> > <br>> > On Aug 15, 2012, at 10:51 AM, "Rodney M. Bates" <rodney_bates@lcwb.coop> wrote:<br>> > <br>> >> <br>> >> <br>> >> On 08/14/2012 10:04 PM, Jay K wrote:<br>> >>> Isn't it safe to take the address of a global?<br>> >>> <br>> >> <br>> >> Do you mean can't you use the ADR function in safe code<br>> >> if you apply it only to a global variable?  The answer<br>> >> to that is no.  The ADR function is illegal altogether in<br>> >> safe code.<br>> >> <br>> >> As to why, I can only speculate, but see below.  I suspect<br>> >> even in this case, it is not as simple as it seems.<br>> >> <br>> >>> <br>> >>> I have something like this:<br>> >>> <br>> >>> <br>> >>> CONST UID_INTEGER = 1234;<br>> >>> CONST UID_FLOAT = 4567;<br>> >>>  ... several more ...<br>> >>> <br>> >>> <br>> >>> TYPE CType = OBJECT .. END;<br>> >>> <br>> >>> <br>> >>> VAR t_int: CType := ...;<br>> >>> VAR t_float: CType := ...;<br>> >>>  ... several more ...<br>> >>> <br>> >>> <br>> >>> MapTypeIdToType(UID_INTEGER, t_int);<br>> >>> MapTypeIdToType(UID_FLOAT, FLOAT);<br>> >>>  ... several more ...<br>> >>> <br>> >>> <br>> >>> but what I really want is more like:<br>> >>> <br>> >>> <br>> >>> TYPE RECORD = BuiltinUid_t =<br>> >>>  typeid: INTEGER;<br>> >>>  ctype: REF CType;<br>> >> <br>> >>           ^UNTRACED REF?  If it were just REF, that would imply that<br>> >> your global variable (the pointer it contains) is a heap object, that<br>> >> it has heap allocator/GC overhead data attached to it, and that the GC<br>> >> should trace it, none of which is true.<br>> >> <br>> >> <br>> >>> END;<br>> >>> <br>> >>> <br>> >>> CONST BuiltinUids = ARRAY OF BuiltinUids {<br>> >>>  BuiltinUids{UID_INTEGER, &t_int},<br>> >>>  BuiltinUids{UID_FLOAT, &t_float},<br>> >> <br>> >> ADR instead of &?  If so, you are still not there, because ADR<br>> >> returns a value of type ADDRESS, i.e., an untraced reference to<br>> >> we-don't-know-what.  Somewhere, you would also have to use a<br>> >> LOOPHOLE to get it to UNTRACED REF CType.<br>> >> <br>> >>>  ... several more ...<br>> >>> };<br>> >>> <br>> >>> <br>> >>> FOR i := FIRST(BuiltinUids) TO LAST(BuiltinUids) DO<br>> >>>  MapTypeIdToType(BuiltinUids[i].typeid, BuiltinUids[i].ctype);<br>> >>> END;<br>> >>> <br>> >> <br>> >> I don't know what the signature of MapTypeIdToType is, but above,<br>> >> you are passing a variable of object type to its 2nd parameter,<br>> >> (which contains a traced reference to the actual heap object).<br>> >> But here, you pass the _address_ of the above.  Inconsistent<br>> >> number of levels of indirection.  A static safe language is<br>> >> much more likely to help with things like this.<br>> >> <br>> >> Maybe you just want to say<br>> >> <br>> >> TYPE RECORD = BuiltinUid_t =<br>> >>  typeid: INTEGER;<br>> >>  ctype: CType;<br>> >> <br>> >> and<br>> >> <br>> >> BuiltinUids{UID_INTEGER, t_int}?<br>> >> <br>> >> This would be equivalent to your first way, and doesn't require any<br>> >> unsafe coding at all.<br>> >> <br>> >> Or, you could do away with global variable t_int altogether and<br>> >> just initialize directly into BuiltinUids[..].ctype with whatever<br>> >> expression you used to initialize t_int.  It looks like your array<br>> >> makes the t_int and cousins redundant.<br>> >> <br>> >>> <br>> >>> Heck, even if these weren't global, is it that unreasonble,<br>> >>> from the programmer's point of view, for the language/compiler<br>> >>> to do some pointer escape analysis and let me take the address<br>> >>> of a local, as long as I don't store it somewhere that outlives<br>> >>> the local?<br>> >>> <br>> >> <br>> >> This is ultimately an undecidable problem and even conservative<br>> >> approximations of reasonable sophistication are far too involved<br>> >> for a language to require of every compiler.<br>> >> <br>> >>> <br>> >>> You can see this particular pattern currently in<br>> >>> m3-sys/m3cc/gcc/gcc/m3cg/parse.c<br>> >>> <br>> >>> <br>> >>> and I'm pretty busy now working on m3-sys/m3back/src/M3C.m3<br>> >>> where I encounter this.<br>> >>> <br>> >>> <br>> >>> Working in safe languages can be frustrating...<br>> >>> <br>> >> <br>> >> It's just an instant/deferred gratification thing.  Safe languages often<br>> >> make you stop and fix it before you run it.  Unsafe languages let you naively<br>> >> forge ahead to the next step, where the bug is likely to be *much* harder to<br>> >> diagnose, assuming you even have enough test cases to notice it at all during<br>> >> development.  Your code here is a good example.<br>> >> <br>> >> Of course, safe languages occasionally make you unnecessarily write a bit more<br>> >> code to do it the safe way.  E.g., the famous fake pointer to the root of a<br>> >> linked list example.  In my personal experience, these times are at least<br>> >> one order of magnitude less frequent than the times safe languages reduce<br>> >> great pain to minor pain, albeit sooner.  If fact, if you are accustomed to<br>> >> thinking in type-safe terms, it is seldom any harder to code it safely in the<br>> >> first place.<br>> >> <br>> >> You're making it too difficult.<br>> >> <br>> >>> <br>> >>> Thank you,<br>> >>> - Jay<br>> >> <br>> > <br></div>                                     </div></body>
</html>