Imagine if you could add common function parameters at the module level, almost as a means of generalizing what OOP achieves with 'this' (an extra parameter added to a bunch of function signatures, automatically placed into the scopes.. now imagine if that was generalised so that you could nest them, i've often wanted that actually..).
it might look something like this,
mod foo<T>(x:Something) {
// 'x' is a shared module level 'parameter' or 'variable',
// -intermediate between global/local
// -usable by all functions declared inside..
fn bar(y:Y) { .. blah blah x.. blah blah y..}...
fn baz(z:Z) { .. blah blah x blah blah z ..}..
}
// .. equivalent to ..
fn foo::bar<T>(y:Y, x:Something){..}
fn foo::baz<T>(z:Z, x:Something){...}
For motivation ,see the conflict between 'no globals / pass everything from above' (traditionally the camp i've been in) versus those who resist it (.. i.e. 'why pass a parameter manually thats repeated many times') .
e.g. I like 'jonathan blows' JAI language goals but he's actually a 'globals apologist' who rejects rusts demand that globals are unsafe{} .. whereas one of the rust-restrictions that I actually like.
Also consider the potential low level benefit of having commonly used values cached in registers;
i started to think about this after posting this, perhaps something more general like this could be a better solution to 'TLS"-esque use-cases.
also consider in addition to something like this Module wide type-parameters, thoughts - #7 by dobkeratops
There are many details here that I don't have a concrete suggestion for. any thoughts generally ? would this be too difficult to do... or would it merely be a nice generalisation of things we can already do, e.g. with nested functions and lambdas.
overall part of my thinking is "we lose some of what C++ classes can do, but we gain another point - the module - that we could use for control"
Think also of effects systems . My preference for 'passing system pointers' around is about clearly marking side effects, e.g. "rendering functions take a rendering object pointer, update functions don't" etc etc. I've had conflict with others who dislike this idea ("passing it all the time is annoying..") and admittedly, it is more verbose.
Could something like this already be achieved through procedural macros;
I guess regular macros could already wrap 'a bunch of function declarations and stuff an extra parameter in' fairly easily (maybe even rolling 'dynamic-scope'-esque stacks to support setting them at various points the calligraph?) but it's really the 'passing of those through callers' (i could roll versions of the functions that retreive their parameters from TLS.. but i'd want those to be efficiently shared as locals instead of being retrieved each time)
i worry a bit about wrapping such large blocks of code that way aswell, e.g. the effect on error messages / giving unexpected behaviour. it also bugs me making an extra nesting level, but could a macro be applied to an entire file? my_macro!{ mod foo; } // bring in 'foo' and wrap it's entirety all in 'my_macro'
i'm not sure what calling this stuff would look like. would it have to behave exactly like an effects system, i.e. tracing the calligraph of functions that use hidden parameters, then inject passing between all of those; how would you pass in the initial value.
are there any other approaches to this sort of thing (e.g. FP currying, accumulating actions and stuffing extra parameters in later). would the module-based idea be building on existing rust structures more.
would something like this just be too unusual to consider.. or would it be quite natural alongside the way existing tools like "global variables", "TLS' already work (and what people already see in OOP languages)
another link, I recall 'long_void' also made something like 'dynamic scope' in his 'rust-flavoured scripting language' GitHub - PistonDevelopers/dyon: A rusty dynamically typed scripting language
Part of the reason I got thinking this way is the loss of overloading, e.g. in the 'manual passing' idea , the 'common system pointer' basically becomes part of the functions name and resolving.. it's mere use distinguishes those functions from others. So again it's more thinking along the lines of 'if modules, traits etc are the rusty-way of thinking, can we leverage them even more?'
actually using it.. there'd have to be some way of injecting the initial values and it would have to figure out how to pass the value between the initial call and consumers (foo::bar(), foo::baz() above) . e.g. lets say a() is outside foo() but traverses some big datastructure to figure out calls to foo. you'd need to say something like foo(x){/* set the parameter 'x' for subsequent calls to foo*/ .. a() /* x actually gets passed to a(), and in turn to calls it makes to foo::bar(..), foo::baz(..) */ }
(see also https://en.wikipedia.org/wiki/Dependency_injection ... i'm personally not keen on talk of 'setting on the client', i prefer tempraries passed when needed..)