<div>Hi!</div><div> </div><div> </div><div>> That's kinda what I meant.</div><div> </div><div>Yes, I understand. But in any case, O7 isn't be classical Oberon.</div><div> </div><div>If you want, I can send article that describe early version of XDS Oberon-2/Modula-2.<br />But, as I remember, all local variable in "parent function" joins to one RECORD.<br />And this record be parameter of "nested function".</div><div> </div><div>Best regards, Victor Miasnikov</div><div> </div><div>09.03.2021, 10:45, "Jay K" <jayk123@hotmail.com>:</div><blockquote><div><div style="color:rgb( 0 , 0 , 0 );font-family:'calibri' , 'helvetica' , sans-serif;font-size:12pt">That's kinda what I meant.</div><div style="color:rgb( 0 , 0 , 0 );font-family:'calibri' , 'helvetica' , sans-serif;font-size:12pt">The problem isn't nested functions, as a naming/hiding thing.</div><div style="color:rgb( 0 , 0 , 0 );font-family:'calibri' , 'helvetica' , sans-serif;font-size:12pt">The problem isn't even nested functions accessing their lexically enclosing locals.</div><div style="color:rgb( 0 , 0 , 0 );font-family:'calibri' , 'helvetica' , sans-serif;font-size:12pt">The problem is taking the address of a nested function.</div><div style="color:rgb( 0 , 0 , 0 );font-family:'calibri' , 'helvetica' , sans-serif;font-size:12pt"> </div><div style="color:rgb( 0 , 0 , 0 );font-family:'calibri' , 'helvetica' , sans-serif;font-size:12pt"> - Jay</div><div><div> </div><div style="color:rgb( 0 , 0 , 0 );font-family:'calibri' , 'helvetica' , sans-serif;font-size:12pt"> </div><hr style="width:98%" /><div><font color="#000000" face="Calibri, sans-serif" style="font-size:11pt"><strong>From:</strong> <a href="mailto:vvm@tut.by" rel="noopener noreferrer">vvm@tut.by</a> <<a href="mailto:vvm@tut.by" rel="noopener noreferrer">vvm@tut.by</a>><br /><strong>Sent:</strong> Tuesday, March 9, 2021 7:32 AM<br /><strong>To:</strong> Jay K <<a href="mailto:jayk123@hotmail.com" rel="noopener noreferrer">jayk123@hotmail.com</a>>; m3devel <<a href="mailto:m3devel@elegosoft.com" rel="noopener noreferrer">m3devel@elegosoft.com</a>><br /><strong>Subject:</strong> Re: [M3devel] closures are a problem</font><div> </div></div><div><div>Hi!</div><div> </div><div> </div><div>  As small remark:</div><div> </div><div>> I think Oberon removed this feature, for example. I just glanced at its specification and it seemed to disallow it.<div> </div><div> </div></div><div>Even Oberon-07 didn't remove nested function. It only can't access to ( read/write) local variable in "parent function".</div><div> </div><div>Others Oberon(s) have "usual" nested functions.<div> </div></div><div> </div><div> </div><div>Best regards, Victor Miasnikov</div><div> </div><div>09.03.2021, 10:11, "Jay K" <<a href="mailto:jayk123@hotmail.com" rel="noopener noreferrer">jayk123@hotmail.com</a>>:</div><blockquote><div><div style="color:rgb( 0 , 0 , 0 );font-family:'calibri' , 'helvetica' , sans-serif;font-size:12pt">Closures are a problem.<div> </div><div>Specifically the ability to take the address of a nested function</div><div>and pass that as a function pointer, and that it has the same</div><div>type as a pointer to a non-nested or C function, and it can access</div><div>the locals of the lexical enclosure (arbitrary levels deep, with recursion,</div><div>but this doesn't make it worse).</div><div> </div><div>The problems:</div><div> </div><div> - The assumption that -1 is not valid code.</div><div> (This value could be changed per system).</div><div> </div><div> - The assumption that code pages are readable.</div><div> Some systems have execute-only memory.</div><div> Reading works on wasm but I don't know what it does, wierd.</div><div> </div><div> - The assumption that reading code pages are meaningful. (wasm?)</div><div> </div><div> - The inability to pass these pointers to C code as function pointers.</div><div> </div><div> - I believe...sorry, I should know better, but I believe in the C backend</div><div>   I play lose with the signatures of functions, passing an extra parameter always,</div><div>   to functions that might not expect it.</div><div>   This likely plays poorly with some environments, such as authenticated ARM function pointers</div><div>   and WebAssembly.</div><div> </div><div>WebAssembly might eventually get a feature to help here.</div><div> </div><div>So, really, I wish this feature was not in the language.</div><div>Barring that, maybe we can remove its use from the base system?</div><div>Maybe have an optional flag or two:</div><div> - prohibit taking address of nested function</div><div> - assume function pointers are not closures</div><div> </div><div>I realize these are different. In that, the second idea in a lower level</div><div>library, breaks use with a higher level library.</div><div> </div><div>I know about several approaches to solve this problem, but none of them are good.</div><div> </div><div>Traditional gcc generates code on the stack.</div><div>  Apple removed this from their compilers years ago.</div><div> </div><div>In some systems you can stamp out identical copies of code, with associated data, and</div><div>manage that like a cheap heap. But I think that still is not worth while.</div><div>It still is not cheap, and it is platform specific.</div><div>Libffi and Mono use this on iPhone for example.</div><div>Libffi will be using it for all systems, at least all Linux systems.</div><div> </div><div>Some systems depend on JIT for this (e.g. CLR on non-iphone).</div><div> </div><div>In normal C code this is handled in a reasonable way, case by case.</div><div> </div><div>For example the qsort_s function (not regular qsort) takes function pointer and a void*.</div><div>The void* is extra context agreed upon between the qsort caller and the function pointer.</div><div>qsort does not know what it is. It can be a pointer to a struct. It can be an integer. It can be ignored.</div><div>There is casting require, but it is ok. It isn't "technically safe", but it is easy to get correct.</div><div> </div><div>This achieves the same result as a "closure".</div><div> </div><div>Occasionally functions, like regular qsort, "forgot" to take the extra void*, and this can be problem indeed.</div><div> </div><div>I'll try to find where in the system we use closures and if they can be "fixed" somehow.</div><div>I would like to soon-ish see if about compiling the system to WebAssembly, via C, and running it in node.js.</div><div>The C output already mostly can compile to WebAssembly, not having done anything.</div><div> </div><div>I think Oberon removed this feature, for example. I just glanced at its specification and it seemed to disallow it.</div><div> </div><div>Thoughts?</div><div> </div>  - Jay</div></div>,<p style="margin-bottom:0;margin-top:0">_______________________________________________<br />M3devel mailing list<br /><a href="mailto:M3devel@elegosoft.com" rel="noopener noreferrer">M3devel@elegosoft.com</a><br /><a href="https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fm3lists.elegosoft.com%2Fmailman%2Flistinfo%2Fm3devel&data=04%7C01%7C%7Cee56d3cc9cf548779a0608d8e2cd8d77%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C637508719763440941%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=V47JobaN9JLsqK4LC6We8eCbEzRONLkW7VRVgIvku2Q%3D&reserved=0" rel="noopener noreferrer">https://m3lists.elegosoft.com/mailman/listinfo/m3devel</a></p></blockquote></div></div></div></blockquote>