oils-for-unix / oils

Oils is our upgrade path from bash to a better language and runtime. It's also for Python and JavaScript users who avoid shell!
http://www.oilshell.org/
Other
2.85k stars 158 forks source link

standard substitution/mutation syntax for transparent Place type, e.g. place[key] in assignments etc. #1794

Open bar-g opened 10 months ago

bar-g commented 10 months ago

(Thanks again for the blog post, gave good hints to sort out the issues.)

Allow standard var[index] syntax for substitution and mutation of Place types, eg. in assignments, or when passed to a func/proc:

reading:

writing:

That would provide for a universal ysh idom to change single dict entries etc. No need to first having to copy and prepare a dict in a separate variable, and then overwriting the whole mutable with ->setValue() at the end.

In 0.19.0 there actually is a bug that seems to expose the requested behavior, however, when passing regular variables and using setvar, instead of only when passing a "place" reference and using setplace: "vars passed to func/proc get mutated at-original-place (not copied)" https://github.com/oilshell/oil/issues/1793 https://github.com/oilshell/oil/issues/1793

With ->setValue()it does not seem possible to set an individual key-value pair, general assignment keywords could be a more consistent idiom.

#context-passing.ysh

const top_level_context = { key: 'value' }

proc a(; context) {
  var context_a = { key: 'value_a' }
  echo "top_level_context: key=$[top_level_context.key]"
  b (&context_a)
}

proc b(; context) {
  echo received context: key=$[context.key]
}

a (&top_level_context)

echo top_level_context: key=$[top_level_context.key]
ysh ysh-0.19.0$ ysh context-passing.ysh

top_level_context: key=value
    echo received context: key=$[context.key]
                                       ^
vars:14: fatal: Dot operator expected Dict, got Place
  ysh context-passing.ysh
  ^~~
[ interactive ]:36: errexit PID 170813: command.Simple failed with status 3

Originally posted by @bar-g in https://github.com/oilshell/oil/issues/1786#issuecomment-1890922341

bar-g commented 9 months ago

After thinking of =-> as an explicit "pointer assignment" (https://github.com/oilshell/oil/issues/1796), and finding it promising way for a consistent syntax, I'm also thinking of the assignment keyword.

Could "pointer" maybe be cleaner and easier to understand than "place"? It could also allow to distinguish between the pointer and the point pointed to.

So specifically, setpoint x = ... could mean "setting the point (called) x to ...".

Also &point (and-point) would nicely rhyme with end-point. :-)

[EDIT: however changing the sigel to =->point could be even more consistent.]

bar-g commented 9 months ago

Maybe the pointer sigel could also be '=->', so =->point would read as "pointer to 'point' ".

And a proc/func signature of (var1 Dict<-=) would mean that var1 needs to be a "Dict pointed to".

andychu commented 9 months ago

I think this is a continuation of #1793 , I clarified there a little

One mitigating thing could be to allow either

&mylist or &&mylist

However they would be no-ops kinda ... I think &&mylist could be a no-op signal mylist

It would not give you a Place, it would just give you the same thing back ?? But it might help non-Python non-JS users become more familiar with the mutable containers ?


var mylist = []

myproc (mylist)  # could be mutated, confusing to shell users

myproc (&&mylist)  # maybe this is a good signal ??   But it doesn't actually change how anything behaves.

Problems

andychu commented 9 months ago

Another thing we might want is the copy() builtin:

myproc (copy(mylist))

This would be a workaround in some cases ?

But again splicing is often useful

myproc @myarray
bar-g commented 9 months ago

-

bar-g commented 9 months ago

-

bar-g commented 9 months ago

-

bar-g commented 9 months ago

Hm, the original problem of this issue actually seems slightly different from the example in your answer.

I think &&mylist could be a no-op signal mylist

It would not give you a Place, it would just give you the same thing back ?? But it might help non-Python non-JS users become more familiar with the mutable containers ?

var mylist = []

myproc (mylist)  # could be mutated, confusing to shell users

myproc (&&mylist)  # maybe this is a good signal ??

Your example is for "calling" the variable in expressions and maybe commands, i.e. where &-prefix creates a place.

The original problem was within a proc/func, where the passed variable has already been "encapsulated" in a Place.

echo $[context.key]
              ^
vars:14: fatal: Dot operator expected Dict, got Place

I think there may be a general conflict of using the &-prefix to create places in calls and to denote dereferencing an existing place or mutable[container] variable (to make the behavior difference apparent).

Maybe place creation should be something different, like var=>&(), and the &-prefix should only be for type-limiting and dereference indicator on the proc/func define-site, and a required behavior and dereference indicator for not-transformed variables passed on the call-site?


The original problem of this issue was, that currently within in a proc/func the actual variable that was passed into the proc/func with the place is itself is not accessible, neither for simple reading in any way, nor for only mutating indexed parts of a passed and "placed" mutable[container]. The only available option seems to be to overwrite/re-assign the whole thing with ->setValue()

bar-g commented 9 months ago

Within a call of a proc/func, could it be simply enough letting !... (EDIT: if that's the successor of &...) not create a place if the type is already a Place?

Would nesting of places be needed for something or not make any sense at all?


And in expressions? that are not passed into procs/funcs, could it be allowed to omit the ! dereference for places, so that they can be used just like mutables? echo "$[local_dict.key] and $[dict_passed_in_Place.key]"