I am trying to port some ActionScript code to VB.Net.
AS code:
public class GridHandler extends Object {
private var grid:Vector.<Vector.<Tile>>;
private var config:Config;
public function GridHandler(param1:Config, param2:Vector.<Vector.<Tile>>) {
this.config = param1;
this.grid = param2;
return;
}// end function
are the values param1 and param2 passed by reference or value?
It sure looks like they are being passed by reference, but I need to be sure.
Thanks.
In AS3, everything is passed by reference - even primitives like ints and Numbers (though they have special operators behinds the scenes to make them act like pass-by-value.
Short answer to your question: yes :)
Link to the relevant docs: http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7f56.html#WS5b3ccc516d4fbf351e63e3d118a9b90204-7f56__WS5b3ccc516d4fbf351e63e3d118a9b90204-7f4c
Related
Problem I need to solve
Is there a way to get the class name of a dart class as a String or a Type object..?
class MyClass {
}
var myClass = MyClass();
I know the property, runtimeType which return the type of the object as a Type object. But is there a similar function for classes?
print(myClass.runtimeType.toString());
What I currently do is creating an object of the class and use runtimeType.
String type = MyClass().runtimeType.toString();
Note: In python there is a variable called __name__ in every class, which does what I need.
My intention
My final goal is to create dart objects using previously saved class names. In this issue they have proposed a method using Maps.
The thing is that I have lots of classes and that method looks messy in my situation.
What I currently do is, save the object type by:
var saving = myClass.runtimeType.toString();
And when loading:
if (saving == MyClass().runtimeType.toString()) {
return MyClass();
}
From your experiences and opinions, can you propose a better solution?
You can use:
var runtimeTypeName = (MyClass).toString();
or for generics:
var runtimeTypeName = T.toString();
The class type can be used as a Type:
Type myType = MyClass;
I have a class that I am creating that looks like this:
class Movie {
final String title, posterPath, overview;
Movie(this.title, this.posterPath, this.overview);
Movie.fromJson(Map json) {
title = json["title"];
posterPath = json["poster_path"];
overview = json['overview';
}
}
I am getting a warning that says that "The final variables 'overview', 'posterPath', & '1' more must be initialized. There are also warnings around each variable saying 'title' can't be used as a setter because it is final.
When I write the constructor using this syntax, the warnings go away:
Movie.fromJson(Map json)
: title = json["title"],
posterPath = json["poster_path"],
overview = json['overview'];
What exactly is going on here?
Dart objects must be fully initialized before anyone gets a reference to the new object. Since the body of a constructor can access this, the object needs to be initialized before entering the constructor body.
To do that, generative Dart constructors have an initializer list, looking similiar to C++, where you can initialize fields, including final fields, but you cannot access the object itself yet. The syntax:
Movie.fromJson(Map json)
: title = json["title"],
posterPath = json["poster_path"],
overview = json['overview'];
uses an initializer list (the list of assignments after the :) to initialize the final instance variables title, posterPath and overview.
The first constructor uses an "initializing formal" this.title to directly put the parameter into the field.
The constructor
Movie(this.title, this.posterPath, this.overview);
is effectively a shorthand for:
Movie(String title, String posterPath, String overview)
: this.title = title, this.posterPath = posterPath, this.overview = overview;
Your constructor can combine all of these and a body:
Movie(this.title, this.posterPath, String overview)
: this.overview = overview ?? "Default Overview!" {
if (title == null) throw ArgumentError.notNull("title");
}
(A const constructor cannot have a body, but it can have an initializer list with some restrictions on the allowed expressions to ensure that they can be evaluated at compile-time).
Dart separates properties initialization from the constructor body.
A constructor has 3 parts :
the name/parameters definition
properties initialization/super call/asserts
A body, similar to a function immediately run on construction
Both the initialization and body parts are optional.
final variables must be initialized on the first 2 parts. They cannot be initialized inside the body.
A full constructor will look like the following :
MyClass(int value)
: assert(value > 0),
property = value,
super();
{
print("Hello World");
}
The main purpose of this initializer part is for body-less constructors which allows const constructors, a dart specific feature. See How does the const constructor actually work? for more details on these.
I just found some documentation around this, & it seams that the second version with the : is what's called the "initializer list" which allows you to initialize instance variables before the constructor body runs.
There is more detail around this in the documentation here.
I have stored variables in a class with their code names.
Suppose I want to get XVG from that class, I want to do
String getIconsURL(String symbol) {
var list = new URLsList();
//symbol = 'XVG'
return list.(symbol);
}
class URLsList{
var XVG = 'some url';
var BTC = 'some url';
}
Can someone help me achieve this or provide me with a better solution?
Dart when used in flutter doesn't support reflection.
If it's text that you want to have directly in your code for some reason, I'd advise using a text replace (using your favourite tool or using intellij's find + replace with regex) to change it into a map, i.e.
final Map<String, String> whee = {
'XVG': 'url 1',
'BTC': 'url 2',
};
Another alternative is saving it as a JSON file in your assets, and then loading it and reading it when the app opens, or even downloading it from a server on first run / when needed (in case the URLs need updating more often than you plan on updating the app). Hardcoding a bunch of data like that isn't necessarily always a good idea.
EDIT: how to use.
final Map<String, String> whee = .....
String getIconsURL(String symbol) {
//symbol = 'XVG'
return whee[symbol];
}
If you define it in a class make sure you set it to static as well so it doesn't make another each time the class is instantiated.
Also, if you want to iterate through them you have the option of using entries, keys, or values - see the Map Class documentation
I'd just implement a getProperty(String name) method or the [] operator like:
class URLsList{
var XVG = 'some url';
var BTC = 'some url';
String get operator [](String key) {
switch(key) {
case 'XVG': return XVG;
case 'BTC': return BTC;
}
}
}
String getIconsURL(String symbol) {
var list = new URLsList();
return list[symbol];
}
You can also use reflectable package that enables you to use reflection-like code by code generation.
Assuming that the class is being created from a JSON Object, you can always use objectName.toJSON() and then use the variable names are array indices to do your computations.
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.
I am using vala.
This is the source code that gives that compile time bug :
private Gee.HashMap<string,VoidFunc> fill_actions()
{
var actions = new Gee.HashMap<string,VoidFunc>();
MainWindow win = window;
actions["t"] = () => _puts(win.title);
return actions;
}
First I tried to access this.window directly but that gave another error so I tried this with a local scope variable.
Error when doing directly this.window :
This access invalid outside of instance methods
It sounds like VoidFunc is declared with [CCode (has_target = false)]. What that means is that no context information is passed to it, and AFAIK that is the only way delegates work as generic type arguments. The reason for this is limitations in C, so assuming VoidFunc looks like this:
[CCode (has_target = false)]
public delegate void VoidFunc ();
What you'll get in C is something like this:
typedef void (*VoidFunc)();
As opposed to something like this if you didn't have the [CCode (has_target = false)]:
typedef void (*VoidFunc)(gpointer user_data);
When you pass around callbacks in C you generally do so with between one and three arguments. Something with all three would look like this:
void foo (VoidFunc void_func, gpointer user_data, GDestroyNotify notify);
The first parameter is the actual function. The second parameter is the value to pass as user_data to the callback, and is what Vala uses to pass context information to the callback (which is what allows it to act as an instance method, or even a closure). The third parameter is used to specify a function to free user_data when it is no longer needed.
What [CCode (has_target = false)] means is that the delegate doesn't have a user_data argument, and therefore cannot be used as a closure or instance method.
The reason this is necessary with a generic argument is that generics look something like this at the C level:
void foo_bar (gpointer data, GDestroyNotify notify);
The first parameter is the data that you want to use as a generic value, the second is actually only added if the generic argument is owned (as it is in the case of the set methods in Gee), and is called with user_data as an argument when user_data is no longer needed.
As you can see, when trying to use a delegate as a generic, there is nowhere to put the user_data argument, which is why Vala only allows delegates without targets to be generic arguments.
The solution is basically to wrap the delegate in a class:
public delegate void VoidFunc ();
public class YourClass {
private class VoidFuncData {
public VoidFunc func;
public VoidFuncData (owned VoidFunc func) {
this.func = (owned) func;
}
}
private Gee.HashMap<string,VoidFuncData> fill_actions() {
var actions = new Gee.HashMap<string,VoidFuncData>();
string win = "win";
actions["t"] = new VoidFuncData (() => GLib.debug (win));
return actions;
}
}