I'm trying to avoid repeating myself by using a closure in the following code:
fn add_raw(&mut self, pair: RawLinkPair) {
let convert = |raw: &RawLink| {
Link{
id: self.get_or_create(raw.name).id,
flow: raw.flow,
}
};
println!("Hive received pair: {}", pair);
let parent = convert(&pair.parent);
let child = convert(&pair.child);
self.link_concepts(parent, child);
}
That doesn't work. It gives me this error:
hive.rs:64:9: 64:13 error: cannot borrow `*self` as mutable because previous closure requires unique access
hive.rs:64 self.link_concepts(parent, child);
^~~~
hive.rs:55:23: 60:10 note: previous borrow of `self` occurs here due to use in closure; the unique capture prevents subsequent moves or borrows of `self` until the borrow ends
hive.rs:55 let convert = |raw: RawLink| {
hive.rs:56 Link{
hive.rs:57 id: self.get_or_create(raw.name).id,
hive.rs:58 flow: raw.flow,
hive.rs:59 }
hive.rs:60 };
hive.rs:65:6: 65:6 note: previous borrow ends here
hive.rs:54 fn add_raw(&mut self, pair: RawLinkPair) {
...
hive.rs:65 }
^
error: aborting due to previous error
In this case I'm not actually saving myself too many keystrokes. I can type everything out by hand and it works fine:
fn add_raw(&mut self, pair: RawLinkPair) {
let parent = Link {
id: self.get_or_create(pair.parent.name).id,
flow: pair.parent.flow,
};
let child = Link {
id: self.get_or_create(pair.child.name).id,
flow: pair.child.flow,
};
self.link_concepts(parent, child);
}
I understand the error (so I think), but:
Is there something wrong with using a closure here in principal or did I just write this wrong?
Is there a more idiomatic way to write this, or at least, how do I satisfy the borrow checker?
This might be a dim question, but why doesn't the borrow just end immediately after the last time convert is called? It seems strange to me especially when I compare it to the bottom version, which ultimately does the same steps minus the closure.
You should be able to fix it like this (something you called "satisfy the borrow checker"):
fn add_raw(&mut self, pair: RawLinkPair) {
let (parent, child) = {
let convert = |raw: RawLink| {
Link{
id: self.get_or_create(raw.name).id,
flow: raw.flow,
}
};
(convert(pair.parent.clone()), convert(pair.child.clone()))
};
self.link_concepts(parent, child);
}
As far as I know, this is something inexpressible in current Rust directly (i.e. without closures). Closures take their environment through &only reference (currently it is only available to compiler), which forbids taking other references until it goes out of scope. It is like &mut reference but not necessarily tied to mutability. Closure environment capture happens upon its creation, so lifetime of this capture extends to the end of the function, hence you're getting the error.
Why closures should take their environment by unique reference I don't know, though.
Related
Learning Dart and using dart_code_metrics to ensure that I write code that meets expectations. One of the rules that is active is avoid-non-null-assertion.
Note, the code below was created to recreate the problem encountered in a larger code base where the value of unitString is taken from a JSON file. As such the program cannot control what is specified in the JSON file.
From pubspec.yaml
environment:
sdk: '>=2.15.0 <3.0.0'
// ignore_for_file: avoid_print
import 'package:qty/qty.dart';
void main() {
const String unitString = 'in';
// unit.Width returns null if unitString is not a unit of Length.
if (Length().unitWith(symbol: unitString) == null) {
print('units $unitString not supported.');
} else {
// The following line triggers avoid-non-null-assertion with the use of !.
final Unit<Length> units = Length().unitWith(symbol: unitString)!;
final qty = Quantity(amount: 0.0, unit: units);
print('Qty = $qty');
}
}
If I don't use ! then I get the following type error:
A value of type 'Unit<Length>?' can't be assigned to a variable of type 'Unit<Length>'.
Try changing the type of the variable, or casting the right-hand type to 'Unit<Length>'.
Casting the right-hand side to
Unit<Length>
fixes the above error but cause a new error when instantiating Quantity() since the constructor expects
Unit<Length>
and not
Unit<Length>?
I assume there is an solution but I'm new to Dart and cannot formulate the correct search query to find the answer.
How can I modify the sample code to make Dart and dart_code_metrics happy?
Your idea of checking for null before using a value is good, it's just not implemented correctly. Dart does automatically promote nullable types to non-null ones when you check for null with an if, but in this case you need to use a temporary variable.
void main() {
const String unitString = 'in';
//Use a temp variable, you could specify the type instead of using just using final
final temp = Length().unitWith(symbol: unitString);
if (temp == null) {
print('units $unitString not supported.');
} else {
final Unit<Length> units = temp;
final qty = Quantity(amount: 0.0, unit: units);
print('Qty = $qty');
}
}
The basic reason for that when you call your unitWith function and see that it's not null the first time, there's no guarantee that the when you call it again that it will still return a non-null value. I think there's another SO question that details this better, but I can't seem to find.
TL;DR
I have a class with no public initializers or instances that passes an instance of itself to a closure in another class. It does this through a mirror of the other class. When I go to access that instance from within the closure, I'm getting a EXC_BAD_ACCESS error, but other parameters passed to the closure are clearly accessible and do not result in a bad access error. I have no idea why. See code below for replication in a new project or a playground.
Detailed Explanation
I've been trying to figure out a way to implement class-specific access control, where multiple specific classes have sole access to another class containing variables and functions to be shared between them. All other classes would not have such access. Kind of like a static class, or a Singleton pattern, but with specific, class-named access control.
I thought I had something that would actually work in pure swift, (which is nice for me since I don't know Objective-C, and only started on swift about 16 months ago.) It's done in an almost anti-swift manner, so just bear with me - my goal is to start with something functional and move it towards elegance and beauty from there.
Even though I'm reasonably confident it should all work, I'm encountering a EXC_BAD_ACCESS error in a very unexpected place.
The "class-specific private" class that you are not allowed to access an instance of unless you are on its "okay" list, we can call the Restricted class.
The class(es) that is(are) allowed access to the Restricted class we can call the Accessor class(es).
The programmer must tell the Restricted class to call a function from the Accessor, and "drop in" an instance of the Restricted class by passing it as a parameter to that function. You do this by passing in the name of the function to be called, an instance of the Accessor class on which to call said function, and any parameters that the function would need in addition to the Restricted class instance.
I could make an enormous switch in the Restricted class, each case of which properly calls each function indicated on each of the Accessor classes...but to get around that excessive overhead/setup, I have the name of the function to be called on the Accessor classes passed in as a string, and accessed through a mirror. Since mirrors only reflect properties and not functions, the function must be a property with an assigned closure, instead of a traditional function.
We can call these closures DropClosures, since their purpose is to have the shared, Restricted class dropped into them. In fact we could call this whole pattern the "DropClosure Pattern". (Or maybe anti-pattern, I know it's kind of gruesome as-is.)
The properties of the "shared" instance of the Restricted class are stored internally as a private static dict (as json, basically). To generate an actual instance of itself, the Restricted class uses a private initializer that accepts that dict as a parameter. After a DropClosure runs with said initialized instance, the Restricted class uses a Mirror of that instance to store any changes back in the "shared" dict, and the instance will go out of scope unless a reference is made to it. So after each DropClosure completes its run, the instance passed to it is more or less useless as a representation of the "shared" aspect of the class, intentionally so.
I only do this because there is no way to require that all references to a certain weak reference also be weak. I don't want a class with access to the weak reference to assign a strong reference to the same instance and keep it in memory, that would defeat the access control goal by allowing the instance to be shared outside of its access scope. Since I can't force the instance to expire once the closure has completed, the next best thing is to remove the motivation for doing so by making the object no longer connected to the shared source after the closure completes.
This all theoretically works, and will compile, and will not throw any swift exceptions when run.
The Accessor (or any class that has an instance of an Accessor) calls RestrictedClass.run(), the run code validates the Accessor instance, finds the DropClosure in that instance, and passes in an instance of the Restricted class to that closure.
However, whenever I try to access that instance from within the DropClosure, it gives me the aforementioned bad access error, seemingly on a C or Objective-C level.
As far as I can tell, the instance should be accessible at this point, and none of the variables being used should be dropping out of scope yet.
At this point I'm totally spitballing - is it possible that there is something in the background that prevents a class with no public initializers from being passed through a mirror? Does it have to do with passing it into a closure called from that mirror? Is there some kind of hidden weak reference that's making the instance get ARC'd?
Please note that I've tried discarding the "weak" wrapper object and only passing in the Restricted instance to the closure, and I get the same bad access error. The error is independent of the instance being weakly referenced.
Code:
import Foundation
typealias DropClosureVoid<T: AnyObject & AccessRestricted> = (_ weaklyConnectedInterface: WeaklyConnectedInterface<T>, _ usingParameters: Any?)->Void
typealias DropClosureAny<T: AnyObject & AccessRestricted> = (_ weaklyConnectedInterface: WeaklyConnectedInterface<T>, _ usingParameters: Any?)->Any?
enum AccessError : Error {
case InvalidFunction
case InvalidAccessClass
}
protocol AccessRestricted {
static func run<T:AnyObject>(_ closureName:String, in classObject: T, with parameters:Any?) throws
static func runAndReturn<T:AnyObject>(_ closureName:String, in classObject: T, with parameters:Any?) throws -> Any?
}
///This class contains an instance that should be expected to only temporarily represent the original, even if a strong reference is made that keeps the value in scope.
class WeaklyConnectedInterface<T:AnyObject> {
weak var value:T?
init(_ value: T) {
self.value = value
}
}
class Accessor {
let restrictedClassPassable:DropClosureVoid<RestrictedAccessClass> = { weaklyConnectedInterface, parameters in
print(weaklyConnectedInterface) // **EXC_BAD_ACCESS error here**
//note that the error above happens even if I pass in the instance directly, without the WeaklyConnectedInterface wrapper.
//It's clearly an issue that occurs when trying to access the instance, whether the instance is wrapped in a the class that makes a weak reference to it or not, which means that it is inaccessible even when strongly referenced.
if let parameterDict = parameters as? [String:String] {
print(parameterDict["paramkey"] ?? "nil")
print(weaklyConnectedInterface)
weaklyConnectedInterface.value?.restrictedVariable = "I've changed the restricted variable"
}
}
let anotherRestrictedClassPassable:DropClosureAny<RestrictedAccessClass> = { weaklyConnectedInterface, parameters in
if let parameterDict = parameters as? [String:String] {
print(parameterDict["paramkey"] ?? "nil")
print(weaklyConnectedInterface.value?.restrictedVariable as Any)
return weaklyConnectedInterface.value?.restrictedVariable
}
return nil
}
func runRestrictedClassPassable() throws {
let functionName = "restrictedClassPassable"
print("trying validateClosureName(functionName)")
try validateClosureName(functionName)//this is in case you refactor/change the function name and the "constant" above is no longer valid
print("trying RestrictedAccessClass.run")
try RestrictedAccessClass.run(functionName, in: self, with: ["paramkey":"paramvalue"])
let returningFunctionName = "anotherRestrictedClassPassable"
print("trying validateClosureName(returningFunctionName)")
try validateClosureName(returningFunctionName)
print("trying RestrictedAccessClass.runAndReturn")
let result = (try RestrictedAccessClass.runAndReturn(returningFunctionName, in: self, with: ["paramkey":"ParamValueChanged"]) as! String?) ?? "NIL, something went wrong"
print("result is \(result)")
}
func validateClosureName(_ name:String) throws {
let mirror = Mirror(reflecting: self)
var functionNameIsPresent = false
for child in mirror.children {
if child.label != nil && child.label! == name {
functionNameIsPresent = true
break
}
}
guard functionNameIsPresent else {
print("invalid function")
throw AccessError.InvalidFunction
}
}
}
extension Mirror {
func getChildrenDict() -> [String:Any]
{
var dict = [String:Any]()
for child in children
{
if let name = child.label
{
dict[name] = child.value
}
}
return dict
}
}
class RestrictedAccessClass:AccessRestricted {
private static var shared:[String:Any] = [
"restrictedVariable" : "You can't access me!"
]
private static func validateType<T>(of classObject:T) throws {
switch classObject {
case is Accessor:
return
default:
print("Invalid access class")
throw AccessError.InvalidAccessClass
}
}
var restrictedVariable:String
private init() {
restrictedVariable = "You can't access me!"
}
private init(from json:[String:Any]) {
restrictedVariable = json["restrictedVariable"] as! String
}
static func run<T:AnyObject>(_ closureName:String, in classObject: T, with parameters:Any?) throws {
print("trying validateType(of: classObject) in run")
try validateType(of: classObject)
for child in Mirror(reflecting: classObject).children {
if let childName = child.label {
if childName == closureName {
let dropClosure = child.value as! DropClosureVoid<RestrictedAccessClass>
let selfInstance = RestrictedAccessClass(from:shared)
let interface = WeaklyConnectedInterface(selfInstance)
dropClosure(interface, parameters)
runCleanup(on: selfInstance)//parses any data changed by the end of the drop closure back into the dict for use in future instances. This means you mustn't try using the instance in an async closure. The correct way to do this would be to call run inside of an async closure, rather than putting an anync closure inside of the drop closure.
_ = interface.value
return
}
}
}
}
static func runAndReturn<T:AnyObject>(_ closureName:String, in classObject: T, with parameters:Any?) throws -> Any? {
print("trying validateType(of: classObject) in runAndReturn")
try validateType(of: classObject)
for child in Mirror(reflecting: classObject).children {
if let childName = child.label {
if childName == closureName {
let dropClosure = child.value as! DropClosureAny<RestrictedAccessClass>
let selfInstance = RestrictedAccessClass(from:shared)
let interface = WeaklyConnectedInterface(selfInstance)
let result = dropClosure(interface, parameters)
runCleanup(on: selfInstance)//parses any data changed by the end of the drop closure back into the dict for use in future instances. This means you mustn't try using the instance in an async closure. The correct way to do this would be to call run inside of an async closure, rather than putting an anync closure inside of the drop closure.
_ = interface.value
return result
}
}
}
return nil
}
private static func runCleanup(on instance:RestrictedAccessClass) {
shared = Mirror(reflecting:instance).getChildrenDict()
//once this function goes out of scope(or shortly thereafter), the instance passed will become useless as a shared resource
}
}
Code to encounter error:
I just put this in a new project's AppDelegate.application(didFinishLaunching). You can put all of the code above and below, in order, in a playground and it will break in the same spot, but not as clearly.
let accessor = Accessor()
do {
try accessor.runRestrictedClassPassable()
}
catch {
print(error.localizedDescription)
}
Updates
Whether zombie objects are turned on or off, I'm getting the same error message from Xcode: Thread 1: EXC_BAD_ACCESS (code=1, address=0x1a1ebac696e)
Running an analysis with Command+Shift+B reveals no warnings.
Running with all of the malloc options enabled reveals the following error:
Thread 1: signal SIGABRT, objc[somenumber]: Attempt to use unknown class 0xSomevalue
This just got weird...
Apparently, the "unknown class" is the project. I found this out by selecting the (i) bubble on the inline object inspector for the Restricted instance that was causing the crash. It gives me the following message:
Printing description of weaklyConnectedInterface:
expression produced error: error:
/var/folders/zq/_x931v493_vbyhrfc25z1yd80000gn/T/expr52-223aa0..swift:1:65:
error: use of undeclared type 'TestProject'
Swift._DebuggerSupport.stringForPrintObject(Swift.UnsafePointer<TestProject.RestrictedAccessClass>(bitPattern: 0x103450690)!.pointee)
^~~~~~~~~~~
I thought that maybe this would happen for other classes, so I tested, and it's able to access other project-level classes just fine. Only for this specific instance is the project "namespace" undefined.
Please find below required modifications (not many)... Tested with Xcode 11.2 / iOS 13.2.
1) made interface inout to pass it as-is original, otherwise it somehow copied loosing type information
typealias DropClosureVoid<T: AnyObject & AccessRestricted> =
(_ weaklyConnectedInterface: inout WeaklyConnectedInterface<T>, _ usingParameters: Any?)->Void
typealias DropClosureAny<T: AnyObject & AccessRestricted> =
(_ weaklyConnectedInterface: inout WeaklyConnectedInterface<T>, _ usingParameters: Any?)->Any?
2) fix places of usage (same in two places)
var interface = WeaklyConnectedInterface(selfInstance) // made var
dropClosure(&interface, parameters) // << copy closure args here was a reason of crash
3) ... and that's it - build & run & output
Note: I would recommend to avoid force unwrap and use the following
if let dropClosure = child.value as? DropClosureVoid<RestrictedAccessClass> {
dropClosure(&interface, parameters)
}
Is there any semantic difference between class-level and member-level self-identifiers in F#? For example, consider this class:
type MyClass2(dataIn) as self =
let data = dataIn
do
self.PrintMessage()
member this.Data = data
member this.PrintMessage() =
printfn "Creating MyClass2 with Data %d" this.Data
Versus this class:
type MyClass2(dataIn) as self =
let data = dataIn
do
self.PrintMessage()
member this.Data = data
member this.PrintMessage() =
printfn "Creating MyClass2 with Data %d" self.Data
The only difference is that the implementation of PrintMessage references this in one vs. self in the other. Is there any difference in semantics? If not, is there a stylistic reason to prefer one over the other?
There's no real semantic difference between the two. As a rule of thumb, I suggest going with your first example - prefer the identifier that's closer in scope, it makes it easier to read and refactor the code later. As a side note, people will usually use this both for class and member-level identifiers, in which case the member-level one shadows class-level one.
In these kind of scenarios, it's useful to look at the compiled code in a disassembler like ILSpy. If you do that, you'll find that the only difference is an extra null check that is inserted in self.Data case.
On the other hand, there is a difference between a class that uses a class-level identifier and one that doesn't (a series of initialization checks get inserted into all the class members). It's best to avoid having them if possible, and your example can be rewritten to not require one.
As mentioned by scrwtp, this seems to be a commonly used identifier and it is my preference. Another very common one is x. I tend to use the class-level identifier when it's used multiple times throughout a class and of course when it's used in the constructor. And in those cases I would use __ (two underscores) as the member level identifier, to signify that the value is ignored. You can't use _ and actually ignore it as it's a compile error, but linting tools will often consider __ as the same thing and avoid giving you a warning about an unused identifier.
When you add a class-level identifier and don't use it you get a warning:
The recursive object reference 'self' is unused. The presence of a recursive object reference adds runtime initialization checks to members in this and derived types. Consider removing this recursive object reference.
Consider this code:
type MyClass() =
member self.X = self
type MyClassAsSelf() as self =
member __.X = self
type MyClassAsSelfUnused() as self = // <-- warning here
member __.X = ()
This is what these classes look like after compiling/decompiling:
public class MyClass
{
public Program.MyClass X
{
get
{
return this;
}
}
public MyClass() : this()
{
}
}
public class MyClassAsSelf
{
internal FSharpRef<Program.MyClassAsSelf> self = new FSharpRef<Program.MyClassAsSelf>(null);
internal int init#22;
public Program.MyClassAsSelf X
{
get
{
if (this.init#22 < 1)
{
LanguagePrimitives.IntrinsicFunctions.FailInit();
}
return LanguagePrimitives.IntrinsicFunctions.CheckThis<Program.MyClassAsSelf>(this.self.contents);
}
}
public MyClassAsSelf()
{
FSharpRef<Program.MyClassAsSelf> self = this.self;
this..ctor();
this.self.contents = this;
this.init#22 = 1;
}
}
public class MyClassAsSelfUnused
{
internal int init#25-1;
public Unit X
{
get
{
if (this.init#25-1 < 1)
{
LanguagePrimitives.IntrinsicFunctions.FailInit();
}
}
}
public MyClassAsSelfUnused()
{
FSharpRef<Program.MyClassAsSelfUnused> self = new FSharpRef<Program.MyClassAsSelfUnused>(null);
FSharpRef<Program.MyClassAsSelfUnused> self2 = self2;
this..ctor();
self.contents = this;
this.init#25-1 = 1;
}
}
Note that there is a check that a variable has been set in the constructor. If the check fails then a function is called: LanguagePrimitives.IntrinsicFunctions.FailInit(). This is the exception thrown:
System.InvalidOperationException: The initialization of an object or value resulted in an object or value being accessed recursively before it was fully initialized.
I guess the warning is there just so that you can avoid the slight overhead of an unnecessary runtime check. However, I don't know how to construct a situation where the error is thrown, so I don't know the exact purpose of the check. Perhaps someone else can shed light on this?
I would like to pass a primitive (int, bool, ...) by reference. I found a discussion about it (paragraph "Passing value types by reference") here: value types in Dart, but I still wonder if there is a way to do it in Dart (except using an object wrapper) ? Any development ?
The Dart language does not support this and I doubt it ever will, but the future will tell.
Primitives will be passed by value, and as already mentioned here, the only way to 'pass primitives by reference' is by wrapping them like:
class PrimitiveWrapper {
var value;
PrimitiveWrapper(this.value);
}
void alter(PrimitiveWrapper data) {
data.value++;
}
main() {
var data = new PrimitiveWrapper(5);
print(data.value); // 5
alter(data);
print(data.value); // 6
}
If you don't want to do that, then you need to find another way around your problem.
One case where I see people needing to pass by reference is that they have some sort of value they want to pass to functions in a class:
class Foo {
void doFoo() {
var i = 0;
...
doBar(i); // We want to alter i in doBar().
...
i++;
}
void doBar(i) {
i++;
}
}
In this case you could just make i a class member instead.
No, wrappers are the only way.
They are passed by reference. It just doesn't matter because the "primitive" types don't have methods to change their internal value.
Correct me if I'm wrong, but maybe you are misunderstanding what "passing by reference" means? I'm assuming you want to do something like param1 = 10 and want this value to still be 10 when you return from your method. But references aren't pointers. When you assign the parameter a new value (with = operator), this change won't be reflected in the calling method. This is still true with non-primitive types (classes).
Example:
class Test {
int val;
Test(this.val);
}
void main() {
Test t = new Test(1);
fn1(t);
print(t.val); // 2
fn2(t);
print(t.val); // still 2, because "t" has been assigned a new instance in fn2()
}
void fn1(Test t) {
print(t.val); // 1
t.val = 2;
}
void fn2(Test t) {
t = new Test(10);
print(t.val); // 10
}
EDIT
I tried to make my answer more clear, based on the comments, but somehow I can't seem to phrase it right without causing more confusion. Basically, when someone coming from Java says "parameters are passed by reference", they mean what a C/C++ developer would mean by saying "parameters are passed as pointers".
As dart is compiled into JavaScript, I tried something that works for JS, and guess what!? It worked for dart!
Basically, what you can do is put your value inside an object, and then any changes made on that field value inside that function will change the value outside that function as well.
Code (You can run this on dartpad.dev)
main() {
var a = {"b": false};
print("Before passing: " + a["b"].toString());
trial(a);
print("After passing: " + a["b"].toString());
}
trial(param) {
param["b"] = true;
}
Output
Before passing: false
After passing: true
One of the way to pass the variables by reference by using the values in List. As arrays or lists are Pass by reference by default.
void main() {
List<String> name=['ali' ,'fana'];
updatename(name);
print(name);
}
updatename(List<String> name){
name[0]='gufran';
}
Try this one, This one of the simplest way to pass by reference.
You can use ValueNotifier
And, you can pass it as ValueListenable to classes or methods that needs to know up-to-date value, but should not edit it:
class Owner {
final theValue = ValueNotifier(true);
final user = User(theValue);
...
}
class User {
final ValueListeneble<bool> theValue;
User(this.theValue);
...
}
It provides more functionality than actually needed, but solves the problem.
If ValueNotifier + ValueListenable do not work for you (you want to make sure the client does not listen to every change of the value, or your package is pure Dart package and thus cannot reference Flutter libraries), use a function:
class Owner {
int _value = 0;
int getValue() => _value;
void increase() => _value++;
}
void main() {
final owner = Owner();
int Function() obtainer = owner.getValue;
print(obtainer());
owner.increase();
print(obtainer());
}
Output will be:
0
1
This approach has memory usage related downside: the obtainer will hold the reference to the owner, and this, even if owner is already not referenced, but obtainer is still reachable, owner will be also reachable
and thus will not be garbage collected.
If you do not want the downside, pass the smaller container than the entire owner:
import 'package:flutter/foundation.dart';
class ListenableAsObtainer<T> implements ValueObtainer<T> {
ListenableAsObtainer(this._listenable);
final ValueListenable<T> _listenable;
#override
T get value => _listenable.value;
}
class FunctionAsObtainer<T> implements ValueObtainer<T> {
FunctionAsObtainer(this._function);
final T Function() _function;
#override
T get value => _function();
}
class ValueAsObtainer<T> implements ValueObtainer<T> {
ValueAsObtainer(this.value);
#override
T value;
}
/// Use this interface when the client needs
/// access to the current value, but does not need the value to be listenable,
/// i.e. [ValueListenable] would be too strong requirement.
abstract class ValueObtainer<T> {
T get value;
}
The usage of FunctionAsObtainer will still result in holding the owner from garbage collection, but two other options will not.
Just to make it clear:
void main() {
var list1 = [0,1,2];
var modifiedList1 = addMutable(list1, 3);
var list2 = [0,1,2];
var modifiedList2 = addImmutable(list2, 3);
print(list1);
print(modifiedList1);
print(list2);
print(modifiedList2);
}
List<int> addMutable(List<int> list, int element){
return list..add(element);
}
List<int> addImmutable(List<int> list, int element){
return [...list, element];
}
Output:
[0, 1, 2, 3]
[0, 1, 2, 3]
[0, 1, 2]
[0, 1, 2, 3]
All variables are passed by value. If a variable contains a primitive (int, bool, etc.), that's it. You got its value. You can do with it whatever you want, it won't affect the source value. If a variable contains an object, what it really contains is a reference to that object.
The reference itself is also passed by value, but the object it references is not passed at all. It just stayed where it was. This means that you can actually make changes to this very object.
Therefore, if you pass a List and if you .add() something to it, you have internally changed it, like it is passed by reference. But if you use the spread operator [...list], you are creating a fresh new copy of it. In most cases that is what you really want to do.
Sounds complicated. Isn't really. Dart is cool.
If I generate a parser using FSYacc will it be thread safe?
The only reason I ask is because the functions
Parsing.rhs_start_pos and Parsing.symbol_end_pos
don't appear to have any state passed into them, which would lead me to assume that they are getting the current NonTerminal/Symbols from a shared location, is this correct?
After reflecting the code I see that they are getting the postion from a static property
internal static IParseState parse_information
{
get
{
return parse_information;
}
set
{
parse_information = value;
}
}
Is this correct? If so what can I do about it?
Edit: I also see a static method called set_parse_state
public static void set_parse_state(IParseState x)
{
parse_information = x;
}
But that still wont solve my problem...
I really don't like to answer my own question, however since this could save someone else a world of grief someday I will.
It turns out that the functions provided in the parsing module are NOT thread safe.
What you can do however is access the parseState "variable", which is of type IParseState, in your nonterminal action.
For example (rough but work with me):
If you have a NonTerminal like
%token<string> NAME
%%
Person:
NAME NAME { $1 (* action *) }
The code that gets generated is:
(fun (parseState : Microsoft.FSharp.Text.Parsing.IParseState) ->
let _1 = (let data = parseState.GetInput(1) in
(Microsoft.FSharp.Core.Operators.unbox data : string)
) in
Microsoft.FSharp.Core.Operators.box((_1) : 'Person)
);
So you can interact with that parseState object in the same fashion.
%token<string> NAME
%%
Person:
NAME NAME { parseState.DoStuff(); }
The rhs_start_pos method basically does this:
let startPos,endPos = parseState.InputRange(n)
and the symbol_end_pos does this:
let startSymb,endSymb = parseState.ResultRange
I hope this helps