I don't think it actually is dynamic scope, It adds an extra set of parameters
to a 3 party situation. One party, the trait declaration has a subset
of these parameters,
The other 2 parties (the caller, and the callee) have the complete set
of parameters.
Quite critically from the perspective of the caller and the callee
everything should be still scoped statically.
Traits add a mechanism not unlike figure 10 of the capability myths
demolished paper
Which limits what capabilities can be granted across the dotted line...
https://srl.cs.jhu.edu/pubs/SRL2003-02.pdf
Not all is well however consider the Ord,
enum Ordering {
Less,
Equal,
Greater,
}
trait Ord {
fn cmp(&self, other: &Self) -> Ordering;
}
I'm going to make up some syntax to make it look more like parameter
passing and use ((extra parameters))
if we add some `context` to it to reverse the order
impl Ord for Foo {
// reverse_order flips it so that less is greater and greater is less.
fn cmp(self: &Foo, other: &Foo)((reverse_order: bool)) -> Ordering
}
I could explain in more depth, but it breaks the transitive property
if you specify different reverse_order contexts.
"It is a logic error for a key to be modified in such a way that the
key’s ordering relative to any other key, as determined by the Ord
trait, changes while it is in the map. This is normally only possible
through Cell, RefCell, global state, I/O, or unsafe code."
https://doc.rust-lang.org/stable/std/collections/struct.BTreeMap.html
Add "or add context via the with keyword" to that list of logic errors.
What this proposal does is it allows an additional parameter to every
trait, you could add it explicitly to every trait already to remove
the dotted line in the figure.
fn cmp<T>(&self, other: &Self)((T)) -> Ordering // I've mentioned this
is a bad idea when it comes to comparison which relies on the absence
of additional context...
It is salvageable if you can explicitly state in traits like Ord that
there may not be any additional context or unit context like
Which would end up with something like:
trait Ord {
fn cmp(&self, other: &Self)((())) -> Ordering;
}
The key thing is that existing rust code can already
fn foo<T>(&self, other: &Self, _: T) -> ...;
Then callers must specify foo(..., ()) and add <()> in the type (When
they want a zero information value to pass).
I am inclined to believe that there is value in something which when
unspecified by the caller defaults to the unit type/value
implicitly...
but must be explicitly opted into by the trait, and when the trait
implementer also opts in the caller must explicitly specify.
but there is a delicate balancing act between the strong property
which were the impetus for traits/type classes that traits like Ord
require and rely on,
and the weaker property desired by the above post.
With the strong property being that there is a single unique
implementation for each type, and the parameters are a closed set
specified by the trait...
the proposal weakens/drops that last property, but it definitely seems
possible to do something in between where the trait gets to choose
whether it is open or closed...
I would hazard a guess that it is roughly equivalent to combination
type-classes/traits along with row polymorphism
Ur/Web is a language (statically scoped) with both which maintains
some strong security properties.
Not going to comment on calling these capabilities though