I have model
class Model {
int counter;
}
now I get a Model object at runtime, so I mark it as dynamic.
dynamic model = new Model();
int counter = 3;
What would be possible way to do equivalent of
model['counter'] = counter;
one thing to mention is that counter from Model is used in the app somewhere, so tree shaking wont remove it.
I am looking for any solution.
class Model {
int counter;
var counterPath = "any way to reference counter field, so I can give the value to it";
}
open to any suggestion or hack :)
One way is to implement a mapping between string name and actual field like
class Model {
int counter;
// reading: print(model['counter']);
operator [](String name) {
switch(name) {
case 'counter':
return counter;
default: throw 'Field $name doesn't exist' in $runtimeType';
}
// writing: model['counter'] = counter;
operator []=(String name, dynamic value) {
switch(name) {
case 'counter':
counter = value;
break;
default: throw 'Field $name doesn't exist' in $runtimeType';
}
}
I'd not recommend this, as using model['string'] makes you loose a lot in maintainability.
But if you truly need it, the best way to achieve this is by using code generation.
In your case, json_serializable may be a good idea. As it will generate a toJson method and a MyClass.fromJson constructor ; without having to change your model in any way.
In the end you'd have
#JsonSerializable()
class Model extends Object with _$ModelSerializerMixin {
int couter;
Model();
factory Model.fromJson(Map<String, dynamic> json) => _$ModelFromJson(json);
}
Which allows you to run the following :
final model = new Model()
..counter = 42;
final modelJson = model.toJson();
modelJson['counter'] = 43;
final result = new Model.fromJson(modelJson); // counter = 43
This may not be the most optimal in term of performances. But it's far less likely to have a bug or require constant edit.
That was for the easy solution.
But that's ugly ; please don't do that.
If you have a real use case where you need reflection then instead of loosing all type check ; create a custom code generator.
There are a few awesome toolings for code generators in dart.
Starting with the lower layer source_gen followed by build to name a few.
Dart team created a lot of tools for code generation ; go take a look !
I've been playing with the Zend Hydrator class today and just found the Naming strategies for converting the input keys on the fly. But when playing with the MapNamingStrategy in conjunction with the ObjectProperty hydrator, it seems to add properties that didn't initially exist in the object if the input array contained them.
Is there any way to restrict it from adding new properties and only populating/hydrating existing ones in the input object?
Still no response on this - what I ended up doing was using one of two scenarios but it is still not ideal. The first is to use Class Reflection myself to get a list of keys that are accessible or to search for standard name accessors for same. (this, of course, would not find magic method accessors)
The second was to pre-define a map that didn't only include mismatched key->property mappings but also included all the one-to-one (matched) key->property mappings then filter the input using PHP's array functions prior to running the hydration using the map's key/value pairs. But this kind of defeats the purpose of using hydration as by that point in time, I may as well have used a foreach loop instead. And it eliminates any ability to use abstract destinations in that you have to know all potential input/output key->property relationships in advance.
I ended up doing my own implementation of the first method (again, that will not necessarily handle magic method accessors) which looks for public properties and/or public accessors fitting the standard camel-cased setPropertyName()/getPropertyName() accessor methods.:
<?php
/**
* simple object hydrator using class reflection to find publicly accessible properties and/or methods
*
* Created by PhpStorm.
* User: scottw
* Date: 12/12/16
* Time: 12:06 PM
*/
namespace Finao\Util;
class SimpleHydrator
{
/**
* whether to reset the keyMap following each hydration to clear the hydrator for other data/object pairs
*
* #var bool $resetMap
*/
private static $resetMap = true;
/**
* associative array of key mappings between incoming data and object property names/accessors
* #var array $keyMap
*/
private static $keyMap = array();
public static function setKeyMap($map) {
if(self::is_assoc($map))
static::$keyMap = $map;
}
public static function populateObject(&$targetObject, $dataArray)
{
if (self::is_assoc($dataArray) && is_object($targetObject)) {
// step through array elements and see if there are matching properties or methods
try {
foreach ($dataArray as $k => $v) {
$key = $k;
if(self::is_assoc(static::$keyMap) && array_key_exists($k))
$key = static::$keyMap[$k];
// if original value contains an object, try populating it if the associated value is also array
$origVal = self::getObjectPropertyValue($targetObject, $key);
if (is_object($origVal) && self::is_assoc($v)) {
self::populateObject($origVal, $v);
$v = $origVal;
}
$accessor = 'set' . ucfirst($key);
if (in_array($key, self::getObjectPublicProperties($targetObject)))
$targetObject->$key = $v;
elseif (in_array($accessor, self::getObjectPublicMethods($targetObject)))
$targetObject->$accessor($v);
}
} catch (\Exception $d) {
// do something with failures
}
if(static::$resetMap) static::$keyMap = array();
}
return $targetObject;
}
public static function getObjectPropertyValue($object, $property)
{
$objectReflection = new \ReflectionClass($object);
if ($objectReflection->hasProperty($property) && $objectReflection->getProperty($property)->isPublic())
return $object->$property;
else {
$accessor = 'get' . ucfirst($property);
if ($objectReflection->hasProperty($accessor) && $objectReflection->getMethod($accessor)->isPublic())
return $object->$accessor();
}
}
public static function getObjectPublicProperties($object)
{
if (is_object($object)) {
$publicProperties = array();
$objectReflection = new \ReflectionClass($object);
foreach ($objectReflection->getProperties(\ReflectionProperty::IS_PUBLIC) as $p)
array_push($publicProperties, $p->name);
return $publicProperties;
}
}
public static function getObjectPublicMethods($object)
{
if (is_object($object)) {
$publicMethods = array();
$objectReflection = new \ReflectionClass($object);
foreach ($objectReflection->getMethods(\ReflectionMethod::IS_PUBLIC) as $p)
array_push($publicMethods, $p->name);
return $publicMethods;
}
}
/**
* Determine if a variable is an associative array.
*
* #param mixed Input variable
* #return boolean If the input variable is an associative array.
* #see http://us2.php.net/manual/en/function.is-array.php
*/
public static function is_assoc($array) {
return (is_array($array) && 0 !== count(array_diff_key($array, array_keys(array_keys($array)))));
}
}
I eventually added a simple key mapping ability to it. (Note that this has not been rigorously tested and, as the name suggests, is just a simple solution.)
I've translation models and I want to run Global query scope that determine the current locale and return the corresponding value upon it or fall back into English if the translation doesn't exist in DB.
I've created a global scope for this purpose and its running good without the ability to fall back into English, so some pages crashes since I'm trying to get property of NULL, and I tried passing some value, but inside the builder I can't determine if the query is going to return null.
How may achieve such thing in Laravel?
my code as follows:
trait WhereLanguage {
/**
* Boot the Where Language trait for a model.
*
* #return void
*/
public static function bootWhereLanguage()
{
static::addGlobalScope(new WhereLanguageScope);
}
}
and the Scope file:
class WhereLanguageScope implements ScopeInterface {
/**
* Apply the scope to a given Eloquent query builder.
*
* #param \Illuminate\Database\Eloquent\Builder $builder
* #param \Illuminate\Database\Eloquent\Model $model
*/
public function apply(Builder $builder, Model $model)
{
$this->addWhereLang($builder);
}
/**
* Remove the scope from the given Eloquent query builder.
*
* #param \Illuminate\Database\Eloquent\Builder $builder
* #param \Illuminate\Database\Eloquent\Model $model
*
* #return void
*/
public function remove(Builder $builder, Model $model)
{
$query = $builder->getQuery();
foreach ((array) $query->wheres as $key => $where)
{
// If the where clause is a soft delete date constraint, we will remove it from
// the query and reset the keys on the wheres. This allows this developer to
// include deleted model in a relationship result set that is lazy loaded.
if ($where['column'] == 'lang_id')
{
unset($query->wheres[$key]);
$query->wheres = array_values($query->wheres);
}
}
}
/**
* Extend Builder with custom method.
*
* #param \Illuminate\Database\Eloquent\Builder $builder
*
*/
protected function addWhereLang(Builder $builder)
{
$builder->macro('whereLang', function(Builder $builder)
{
// here 1 is ID for English,
// 48 Arabic, 17 Netherlands...etc
// and It was the App:currentlocale() passed into Language model to determine the ID of current locale.
// but for testing now I hard coded it with ID of 48
$builder->where('lang_id','=','48');
return $builder;
});
}
}
Usage example:
$title = $centre->translations()->whereLang()->first()->name;
Where Centre is my model without localization, and translation is the name of method that handling the relation between Centre & CentreTranslation.
btw I don't want to pass variable obligately.
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 want to use a Tuple but in C# 2, it does not exist. I think to replace it by KeyValuePair.
Is it the best way to do this ?
A simple class holding two generic members is probably the best option. This is essentially what Tuple<T1,T2> is.
If you know the types you are using, it is better to create a class with members of those types - this way you can use good naming for the class and members to ensure good readability (which a generic type like Tuple obscures).
From you comment, I would suggest that creating a small wrapper class (or possibly struct) to hold the int values will be the best choice.
Untested:
public class Point
{
public Point(int xPos, int yPos)
{
this.xPos = xPos;
this.yPos = yPos;
}
int xPos;
int yPos;
public int XPos { get { return xPos;} set { xPos = value;} }
public int YPos { get { return yPos;} set { yPos = value;} }
}
If you use your Tuple always like Tuple<T1,T2> then you can switch easily to KeyValuePair<T1,T2> with no problems.
The only difference is that you have to use the Key and Value properties instead of the ItemN property of the Tuple.