I have an abstract type which is being used in few concrete objects and a record type that contains a list of that abstract type.
public type AbstractType object {
isolated function profile() returns string;
};
public isolated class ConcreteImpl1 {
*AbstractType;
isolated function profile() returns string {
return "concreteOne";
}
}
public isolated class ConcreteImpl2 {
*AbstractType;
isolated function profile() returns string {
return "concreteTwo";
}
}
public type ImplHolderType record {
AbstractType[] implementations;
};
I have initialized ImplHolderType
with 2 objects and trying to access one of the values inside an isolated function.
final ImplHolderType implList = {
implementations: [new ConcreteImpl1(), new ConcreteImpl2()]
};
isolated resource function get sample/profile() returns string {
AbstractType abstractType = implList.implementations[0];
return abstractType.profile();
}
Here I'm getting an error when I'm trying to access the list (implList.implementations[0]
) saying invalid access of mutable storage
.
Can you suggest a workaround that I can do to avoid this error?
Since implList
is mutable (even though it is final, the fields can still be updated), you can't access it within an isolated function. You could make implList
an isolated variable and then access it within the isolated function. You'll have to use a lock statement when accessing.
isolated ImplHolderType implList = {
implementations: [new ConcreteImpl1(), new ConcreteImpl2()]
};
service on new http:Listener(8080) {
isolated resource function get sample/profile() returns string {
lock {
return implList.implementations[0].profile();
}
}
}
https://ballerina.io/learn/by-example/isolated-variables
https://ballerina.io/learn/by-example/#concurrency-safety
Alternatively, if your implementation classes won't have any mutable fields, you can make them readonly
classes, and then make implList
be of type readonly & ImplHolderType
, which will make it be immutable. Then you would be able to access it in an isolated function without a lock statement.
import ballerina/http;
public type AbstractType object {
isolated function profile() returns string;
};
public readonly class ConcreteImpl1 {
*AbstractType;
isolated function profile() returns string {
return "concreteOne";
}
}
public readonly class ConcreteImpl2 {
*AbstractType;
isolated function profile() returns string {
return "concreteTwo";
}
}
public type ImplHolderType record {
AbstractType[] implementations;
};
final readonly & ImplHolderType implList = {
implementations: [new ConcreteImpl1(), new ConcreteImpl2()]
};
service on new http:Listener(8080) {
isolated resource function get sample/profile() returns string {
return implList.implementations[0].profile();
}
}