<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><br /></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><br /></div></div><div> </div><div> </div><div>Best regards, Victor Miasnikov</div><div> </div><div>09.03.2021, 10:11, "Jay K" <jayk123@hotmail.com>:</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>_______________________________________________<br />M3devel mailing list<br /><a href="mailto:M3devel@elegosoft.com" rel="noopener noreferrer">M3devel@elegosoft.com</a><br /><a href="https://m3lists.elegosoft.com/mailman/listinfo/m3devel" rel="noopener noreferrer">https://m3lists.elegosoft.com/mailman/listinfo/m3devel</a></p></blockquote>