Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transferring in/out a structure of isolated objects #855

Open
MaryamZi opened this issue May 25, 2021 · 7 comments
Open

Transferring in/out a structure of isolated objects #855

MaryamZi opened this issue May 25, 2021 · 7 comments
Labels
Area/Lang Relates to the Ballerina language specification design/usability Design does not work well for some tasks Type/Improvement Enhancement to language design
Milestone

Comments

@MaryamZi
Copy link
Member

Description:
Please consider the following example.

isolated class Foo {
   private int i = 1;

   function get() returns int {
      lock {
         return self.i;
      }
   }

   function increment() {
      lock {
         self.i += 1;
      }
   }
}

isolated class Bar {
   private Foo[] arr = [];

   function getArr() returns Foo[] {
      // Want to return an array that contains the same members as `self.arr` here.
   }
}

I don't think it is currently possible to do what's required in getArr.

Both the following are invalid.

Case I

   function getArr() returns Foo[] {
      lock {
         return self.arr; // ERROR: invalid attempt to transfer out, not an isolated expression.
      }
   }

Case II

   function getArr() returns Foo[] {
      Foo[] copy = [];
      lock {
         foreach Foo foo in self.arr {
            copy.push(foo); // ERROR: invalid attempt to transfer in `copy`
         }
      }
      return copy;
   }

In Case I, clone or cloneReadOnly cannot be used either, since Foo is not a subtype of value:Cloneable.

There were some scenarios where the standard library had a similar requirement too, but they were generally able to use read-only classes. But in cases where only a field would change previously they now have to create a new object since the original value cannot be updated.

@MaryamZi MaryamZi added the design/usability Design does not work well for some tasks label May 25, 2021
@MaryamZi
Copy link
Member Author

Also wondering if spread fields/expressions can help to a certain extent.

Using a spread field in a mapping constructor as an example (since we don't have list spread yet), if the following is allowed, I guess we can use this in the mapping case?

isolated class Bar {
   private map<Foo> m = {};

   function getMap() returns map<Foo> {
      lock {
         return {...self.m};
      }
   }
}

The implementation does not seem to allow this at the moment though.

@jclark
Copy link
Collaborator

jclark commented May 25, 2021

Relates to #52.

@jclark jclark added this to the Swan Lake polish milestone May 25, 2021
@MaryamZi
Copy link
Member Author

There's also a related scenario when the structure has a combination of isolated objects and values that belong to value:Cloneable.

I guess we can still use the spread operator if the values that belong to value:Cloneable are subtypes of readonly.

type Config record {|
   int[] & readonly a;
   IsolatedClass b;
|};

But this would not be possible if the types of the rest of the fields are not subtypes of readonly.

type Config record {|
   int[] a;
   IsolatedClass b;
   map<boolean> c;
|};

isolated class Foo {
   private Config c;

   isolated function init(Config con) {
      self.c = con; // ERROR: RHS is not an isolated expression and cannot use `clone`/`cloneReadOnly`.
                    // `self.c = {...con};` can't be used because `a` and `c` are mutable.
   }
}

Although we can get this to work by separating out the isolated objects and the values that belong to value:Cloneable and only using clone/cloneReadOnly with the latter, I don't think it will scale with nested records that have isolated objects as field types.

isolated class Foo {
   private Config c;

   isolated function init(Config con) {
      var {b, ...rest} = con;
      self.c = {b, ...rest.clone()};
   }
}

Could be related to #784

@jclark
Copy link
Collaborator

jclark commented May 25, 2021

Please make #855 (comment) a separate issue.

@jclark
Copy link
Collaborator

jclark commented May 25, 2021

Can we make a query expression work?

from var f in self.array select f

@MaryamZi
Copy link
Member Author

Please make #855 (comment) a separate issue.

Created #856

Can we make a query expression work?

from var f in self.array select f

The implementation seems to have inadvertently allowed this already for transferring out. If the iterable value used in the from-clause is not an invalid transfer in and f is an isolated expression, the query expression currently seems to be considered an isolated expression.

@MaryamZi
Copy link
Member Author

This is allowed at the moment when we transfer out (to an array using member access) one isolated object at a time.

isolated class Bar {
    private Foo[] arr = [];

    function getArr() returns Foo[] {
        Foo[] copy = [];
        lock {
            foreach [int, Foo] [index, foo] in self.arr.enumerate() {
                copy[index] = foo; // transfer out
            }
        }
        return copy;
    }
}

isolated class Foo {
    private int i = 1;

    function get() returns int {
        lock {
            return self.i;
        }
    }

    function increment() {
        lock {
            self.i += 1;
        }
    }
}

@MaryamZi MaryamZi modified the milestones: Nutcracker, 2023R2 Jun 21, 2023
@anupama-pathirage anupama-pathirage added Type/Improvement Enhancement to language design Area/Lang Relates to the Ballerina language specification labels Nov 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area/Lang Relates to the Ballerina language specification design/usability Design does not work well for some tasks Type/Improvement Enhancement to language design
Projects
None yet
Development

No branches or pull requests

3 participants