{"action":"created","issue":{"url":"https://api.github.com/repos/keean/zenscript/issues/35","repository_url":"https://api.github.com/repos/keean/zenscript","labels_url":"https://api.github.com/repos/keean/zenscript/issues/35/labels{/name}","comments_url":"https://api.github.com/repos/keean/zenscript/issues/35/comments","events_url":"https://api.github.com/repos/keean/zenscript/issues/35/events","html_url":"https://github.com/keean/zenscript/issues/35","id":243345358,"node_id":"MDU6SXNzdWUyNDMzNDUzNTg=","number":35,"title":"WD-40 (for reducing Rust with the next mainstream language)","user":{"login":"shelby3","id":247731,"node_id":"MDQ6VXNlcjI0NzczMQ==","avatar_url":"https://avatars3.githubusercontent.com/u/247731?v=4","gravatar_id":"","url":"https://api.github.com/users/shelby3","html_url":"https://github.com/shelby3","followers_url":"https://api.github.com/users/shelby3/followers","following_url":"https://api.github.com/users/shelby3/following{/other_user}","gists_url":"https://api.github.com/users/shelby3/gists{/gist_id}","starred_url":"https://api.github.com/users/shelby3/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/shelby3/subscriptions","organizations_url":"https://api.github.com/users/shelby3/orgs","repos_url":"https://api.github.com/users/shelby3/repos","events_url":"https://api.github.com/users/shelby3/events{/privacy}","received_events_url":"https://api.github.com/users/shelby3/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":354,"created_at":"2017-07-17T09:55:13Z","updated_at":"2018-12-27T00:05:36Z","closed_at":null,"author_association":"NONE","body":"⁣ | ⁣\r\n----- | -----\r\n![](https://upload.wikimedia.org/wikipedia/commons/thumb/e/ed/WD-40_Smart_Straw.JPG/103px-WD-40_Smart_Straw.JPG)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | I propose a (rough sketch for a) language design that I posit while attempting to maintain the most significant opportunities for performance (e.g. monomorphisation) would have superior tradeoffs  than Rust in the areas of complexity bloat, design freedom, and benefits versus inflexibility/tsuris of static code analysis. It would have the HLL feel of JavaScript with the LLL control of C++ without all the complexity and unnecessary abstractions (e.g. not the anti-patterns OOP subclassing and not `shared_ptr` as the default over GC).\r\n\r\n<dl>\r\n  <dt>GC Exclusion Axiom:</dt>\r\n  <dd>Afaics, presuming (<sup><sub>enforcement of <a href='https://doc.rust-lang.org/book/second-edition/ch10-03-lifetime-syntax.html#the-borrow-checker'>block scope lifetimes</a> and</sub></sup>) all functions input (<sup><sub>mutable or immutable because <a href='https://github.com/keean/zenscript/issues/17#issuecomment-315656536'>we don’t care in a single-threaded model</a></sub></sup>) borrows—i.e. don’t take lifetime ownership (<sup><sub>note callbacks take lifetime ownership</sub></sup>)—then GC is not required for provable use-after-free (<sup><sub>aka <a href='https://doc.rust-lang.org/book/second-edition/ch04-02-references-and-borrowing.html#dangling-references'>dangling reference</a>/pointer</sub></sup>) safety. However, for <i>dynamic</i> data structures that share references (<sup><sub>e.g. directed graphs with <a href='https://en.wikipedia.org/wiki/Directed_graph#Indegree_and_outdegree'>in-degree > 1</a></sub></sup>), then GC references are much more convenient and performant than the alternative of representing the references with array indices. Note functions that would otherwise take ownership can take ownership of a (GC referenced or unboxed¹) deep copy/clone instead. However where deep cloning would be too costly in terms of performance and memory consumption, shared GC references may be preferred. <sup><sub>Where GC is employed we have protection against memory leaks which <a href='https://github.com/keean/zenscript/issues/17#issuecomment-314963860'>Rust does not provide</a>, except with an <a href='https://github.com/keean/zenscript/issues/34#issuecomment-310898051'>inferior except prompt/deterministic</a> reference counting smart pointer paradigm <a href='https://doc.rust-lang.org/book/second-edition/ch15-04-rc.html'><code>Rc&lt;T></code></a>.</sub></sup></dd>\r\n</dl>\r\n\r\nAfaics, there are some marvelous simplifying implications of this axiom:\r\n\r\n1. Presuming all functions adhere except where they declare references to be GC, afaics the compiler can _automatically_ implement RAII (in `try-finally` blocks² with an equivalent `finally` [concept for](https://github.com/keean/zenscript/issues/17#issuecomment-318685944) `Promise` callbacks) for deterministic memory deallocation (and _automatically_ deterministically destruct instances of a type that have a destructor¹ which is [a major feature lacking from GC languages](http://blog.skylight.io/rust-means-never-having-to-close-a-socket/#theownershipsystem) and the `with` of Python being inferior because it is manual and [object isn’t deallocated deterministically](https://stackoverflow.com/questions/5071121/raii-in-python-automatic-destruction-when-leaving-a-scope); <sup><sub>noting that such types can not used with GC references directly or indirectly as a member of a data structure that is GC referenced</sub></sup>).\r\n\r\n2. Afaics, the same code will be sound and applicable whether the data structures are implemented by compiler unboxed without GC or boxed with GC. In other words, other than the aforementioned explicit GC references for algorithmic convenience and performance, the programmer never needs to indicate whether the data structures should be boxed or unboxed³. I want to strip away the noise/complexity of `Ref<>`, `Box<>`, etc.. For read-only inputs (i.e. the unannotated default) the programmer need not even think about whether the inputs are cloned-by-value (i.e. primitive type) or passed-by-reference; and cloned-by-value type inputs should never be allowed to be annotated as mutable on the function signature (<sup><sub>although they can be mutated inside the function body unless they explicitly annotated read-only and the point being that the programmer never needs to think about whether the type is primitive or not and can see if there is a mutability implication by looking at the function signature</sub></sup>). Although I presume an optimizing compiler will always strive for unboxed (because this will be more performant), if we start writing code in say TypeScript we can strive to adhere to this pattern (or have our compiler generate TypeScript) without all the unboxing mess if we so desire.\r\n\r\n3. Goodbye to Rust’s lifetime parameters and 3 kinds of pointers noise/tsuris/complexity; and  [due to the proposed single-threaded _concurrency_ event model](https://github.com/keean/zenscript/issues/17#issuecomment-315656536) goodbye also to Rust’s mutability borrowing restrictions/complexity/tsuris.\r\n\r\n4. When thinking about interfacing with ASM.js (or Webassembly aka WASM) with minimum (or no) marshaling overhead, then since (which IMO is a [major paradigmatic flaw](http://mrale.ph/blog/2013/03/28/why-asmjs-bothers-me.html#odinmonkey-makes-javascript-fast-with-insane-optimizations)) there is no way yet to have those [interact directly with GC references](https://stackoverflow.com/questions/17564972/handwriting-asm-js-how-can-you-track-javascript-objects-in-the-heap) (ostensibly because since there is no static typing then JavaScript thinks these are unbounded polymorphic, i.e. `Any` aka `Object`), we can (until some future where we write our own VM) favor unboxed and [`malloc`ing these via Emscripten](https://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html#access-memory-from-javascript) (or similar transpilation to ASM.js/WASM of our own C-like language features).\r\n\r\n¹ But not cloning resources such as file handles.\r\n\r\n² And [Rust’s error handling](https://doc.rust-lang.org/book/second-edition/ch09-00-error-handling.html) has no `try` (`panic!` is doesn't `throw` an error up the stack call hierarchy) and instead forces all exceptions to be bubbled up as [`Result<T, E>`](https://doc.rust-lang.org/book/second-edition/ch09-02-recoverable-errors-with-result.html) return values which is excessive boilerplate noise/tsuris.\r\n\r\n³ Even arrays of data structures that have variable sized members such as `String` can be cleverly implemented (by a library or the compiler) to use indices byte offsets into a second array which contains the variable sized values. This can even work with mutable variable size values, by creating a new value at the end of the second array growing the array as necessary and/or implementing a `malloc` and `free` on the second array, i.e. this second array heap is freed from the parent heap as a monolith. Note if the second array is encapsulated so it can never be referenced directly, then it can be repositioned in virtual address space as needed to minimize virtual address space fragmentation. Monomorphisation could make such libraries more efficient.\r\n\r\nNote _bounded_ polymorphism never absolutely requires boxing. Unbounded polymorphism would but we are refusing to support `Any`, i.e. all unbounded polymorphism in modules must be bounded when consumed by compiled/linked code.\r\n\r\nSubsequent discussion in this thread will explain further the rough sketch so that readers can gain clarity. Let’s see what caveats and flaws are revealed via discussion. I look forward to @keean’s feedback and perhaps he will explain to what degree it corresponds to some features of the Ada PL.\r\n\r\nI do not claim any of these ideas are novel inventions. @keean has alluded to for example cloning as an alternative to lifetimes and/or GC. What I am doing above is making a more holistic presentation of various ideas that have been floating around.\r\n\r\nOf course [typeclasses or ML functor/modules](https://github.com/keean/zenscript/issues/14#issuecomment-308722477) on top of this for HLL abstractions. If typeclasses, there is [an option to go with implicit function arguments](https://github.com/keean/zenscript/issues/30#issuecomment-302123983) instead of `requires`, which makes it more readily implementable in TypeScript.\r\n\r\n@shelby [wrote](https://github.com/keean/zenscript/issues/17#issuecomment-315656536):\r\n> My expectation is that in Rust the programmer will often need to resort to unsafe code to obtain the necessary freedom. My overriding concern is the K.I.S.S. principle and the amount of the complexity budget consumed for the benefits attained.\r\n\r\n@shelby3 [wrote](https://github.com/keean/zenscript/issues/34#issuecomment-315576966):\r\n> …the goals that one justifies employing static typing (“_better structure/abstraction, have more readable/maintainable code, and giving stronger guarantees about safety, lack of bugs, and lack of exploits_”)…\r\n>\r\n> A valid argument against static typing which I have made on these issues threads, is that no static abstraction can be 100% leak-free. Meaning that eventually we always end up having to violate the invariants of the abstraction, or moreover that it becomes very convoluted to maintain type safety and have complete degrees-of-freedom of expression. So then static typing becomes a negative factor for productivity instead of a positive one. This is why selecting which abstractions to enforce with a compiler is an engineering design challenge (arguably even perhaps an art) of matching to use cases.\r\n\r\nEDIT: on the coding for readability point, [_“Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.”_](http://ruby.zigzo.com/2014/08/01/who-said-that-one-violent-psychopath-quote/)\r\n\r\n@shelby3 [wrote](https://github.com/keean/zenscript/issues/17#issuecomment-313808940):\r\n> …there is diminishing return from static checking complexity because we can not statically check every clever algorithm and design paradigm that programmers will come up with. I think he had mentioned fighting with type systems.\r\n>\r\n> I am interested to explore static typing that does not frustrate programmers.\r\n> …\r\n> Disagree that Rust’s balance of flexibility and tsuris is ideally suited to most apps.\r\n\r\n@shelby3 [wrote](https://github.com/keean/zenscript/issues/17#issuecomment-313713206):\r\n> Additionally it’s the noise of extreme static checking such as the lifetime parameters (in addition to generic parameters and normal kinds of static types) on every function in Rust… GC is so much more elegant. I understand certain real-time use cases will not tolerate GC pauses (although we did also discuss V8’s incremental mark-and-sweep upthread) and more optimized by zero overhead abstractions (e.g. no runtime overhead for deciding which to deallocate)\r\n\r\n@shelby3 [wrote](https://github.com/keean/zenscript/issues/17#issuecomment-313578132):\r\n> Perhaps we will eventually think of some low-complexity abstraction that gives us non-marshaled integration for tree data structures between HLL and LLL, and perhaps we can even prove borrowing and lifetimes statically. But I suspect we can not without heading towards the complexity of C++ and Rust.\r\n\r\n@keean [wrote](https://github.com/keean/zenscript/issues/17#issuecomment-312874353):\r\n> I would not write a web service in 'C' or even 'Rust' ever, this is really ideal ground for a garbage collected language. I would use Node (TypeScript), Django(Python) or 'Go'.\r\n\r\n@keean [wrote](https://github.com/keean/zenscript/issues/17#issuecomment-312443168):\r\n> My view is there needs to be a high-level-language and a low-level-language that share enough memory-layout and data-structure that data can easily be passed backward and forward.\r\n\r\n@shelby3 wrote:\r\n> I am wanting to move away from such clusterfucks of never ending aggregation of complexity.\r\n\r\n> I am not going to try to argue that Rust has no use cases.\r\n> \r\n> But I want to create a mainstream programming language used by millions of programmers.\r\n> \r\n> Do you want to compete with Rust?\r\n\r\n@keean [replied](https://github.com/keean/zenscript/issues/17#issuecomment-312446734):\r\n> @shelby3 wrote:\r\n>> Once we start heading for Rust’s three different kinds of pointers, then I will think we have failed to make a clean high-level language for the masses.\r\n>\r\n> Here we agree."},"comment":{"url":"https://api.github.com/repos/keean/zenscript/issues/comments/450043812","html_url":"https://github.com/keean/zenscript/issues/35#issuecomment-450043812","issue_url":"https://api.github.com/repos/keean/zenscript/issues/35","id":450043812,"node_id":"MDEyOklzc3VlQ29tbWVudDQ1MDA0MzgxMg==","user":{"login":"keean","id":508384,"node_id":"MDQ6VXNlcjUwODM4NA==","avatar_url":"https://avatars2.githubusercontent.com/u/508384?v=4","gravatar_id":"","url":"https://api.github.com/users/keean","html_url":"https://github.com/keean","followers_url":"https://api.github.com/users/keean/followers","following_url":"https://api.github.com/users/keean/following{/other_user}","gists_url":"https://api.github.com/users/keean/gists{/gist_id}","starred_url":"https://api.github.com/users/keean/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/keean/subscriptions","organizations_url":"https://api.github.com/users/keean/orgs","repos_url":"https://api.github.com/users/keean/repos","events_url":"https://api.github.com/users/keean/events{/privacy}","received_events_url":"https://api.github.com/users/keean/received_events","type":"User","site_admin":false},"created_at":"2018-12-27T00:05:36Z","updated_at":"2018-12-27T00:05:36Z","author_association":"OWNER","body":"@shelby3 I don't have time to go chasing links, and I don't see anything that's discusses problems with the distribuion of operators above. I remember the problems with Pony that we discussed, but I don't see how that is relevant to the treatment of unions an intersection above."}}
{"actor":{"display_login":"keean"}}