Dart: Reference a variable name from the variable itself - dart

I’m trying to get the variable name instead of the value to pass it to another method
eg.
String myString = "xyz";
String getVariableName(String s){
// What i want is if the above string is passed [getVariableName(myString)]
//i want it to return ['myString']
}

This is generally not possible. At best, if there are a finite number of String variables you care about, you could manually make a collection of them, and then search it:
final stringVariables = <String, String Function()>{
'myString': () => myString,
'myOtherString': () => myOtherString,
};
var myString = 'xyz';
var myOtherString = 'abc';
String getVariableName(String s) {
for (var entry in stringVariables.entries) {
if (entry.value() == s) {
return entry.key;
}
}
return '';
}
void main() {
print(getVariableName('xyz')); // Prints: myString
myString = 'foo';
print(getVariableName('foo')); // Prints: myString
}
Note that stringVariables's above must use a Function as a thunk to delay evaluation of the variable; otherwise the variable name would be associated with whatever value it happened to have when stringVariables is first accessed and wouldn't work if your variables are reassigned.
All that said, I don't really recommend doing any of this. This sounds like an XY problem. You should be asking about whatever it is you ultimately want to do, and there probably is a better way to accomplish that task.

Related

Truthy and falsy values in Dart programming language

I just stand in front of a very weird part in dart, I didn't find an answer on the internet, No truthy and falsy values in dart?!
for example,
const x = "foo";
void main(){
if(x){
print("x is set")
}
}
In JavaScript we do this things very easily, how can I do that in Dart?!
Dart is a statically typed language, so x is a String, and you can't check if a string is true or false.
if you want to check if x has a value or not, you can do the following
String x = 'hi';
if (x?.isNotEmpty ?? false) {
print("x is set");
}
After some researches, I've found that in order to check for a dynamiclly assigned variable, where in case you're not sure if the variable will be set to a number or a string for example, you need to check if the variable is not equal to null.
For example:
void main(){
var a;
if(true){
a = "The variable is set to string";
}
else if(false){
a = 12; //the variable is set to a number
}
//Now, to check:
if(a != null){
print("A is set, WOW Dart is working! I thought it's garbage!");
}
}
In case the both statements are false, the variable will still be a null.

How to return two specific types from a generic method?

T getValue<T>(int i) {
if (T == String) return '$i'; // Error
return i; // Error
}
void main() {
var s = getValue<String>(1);
var i = getValue<int>(1);
}
I want getValue to return string if T is String and int otherwise. How to do that?
You can't restrict the type parameter to just int or String, so it will have to accept more than that (at least their least common supertype, Object, so basically any type).
It's not a particularly helpful way to code. It's possible, but not recommended:
T getValue<T>(int i) {
if (i is T) return i;
return "$i" as T;
}
This will return the int if T allows it (so T being any of int, or a super type of int, which is num, Object, dynamic or void, or any number of Comparable<X> wrappings around any any of those supertypes), and otherwise try to return a string. That will fail with a type error unless T is String (since we've already ruled out all supertypes of String).
You can still call it as getValue<bool>(42) and watch it fail, so the type argument doesn't help with correctness.
It's not particularly effective. I'd rather do:
dynamic getValue(int i, {bool toString = false}) {
if (toString) return "$i";
return i;
}
and call it as:
String x = getValue(42, toString: true); // Add `as String` if you disable downcasts.
int y = getValue(42); // And `as int` here.
The type parameter is really just making things harder. You are going to cast or type-check the result anyway, so might as well do it at the call point, rather than introduce type variables that aren't actually preventing misuse anyway.
(I'd probably just do two different functions, but I assume that there is a reason for wanting one function).
As I mentioned in the comments, I don't see any way that you could use your generic as the return type of your getValue function. Even assuming the return under the if statement worked, there is nothing that can be done about trying to return int i when List is passed as the type. You'll be trying to return an int as a List.
If you change it to dynamic, your code will work fine as it's just using the generic as another parameter.
dynamic getValue<T>(int i) {
if (T == String) return '$i';
return i;
}
void main() {
var s = getValue<String>(1);
var i = getValue<int>(1);
}

Using an 'is' expression when the right-hand operand is a variable?

I am trying to write a function that takes two arguments: givenType and targetType. If these two arguments match, I want givenType to be returned, otherwise null.
For this objective, I am trying to utilize Dart's is expression (maybe there is a better way to go about it, I am open to suggestions). Initially, I thought it would be as simple as writing this:
matchesTarget(givenType, targetType) {
if (givenType is targetType) {
return givenType;
}
return null;
}
But this produces an error:
The name 'targetType' isn't a type and can't be used in an 'is'
expression. Try correcting the name to match an existing
type.dart(type_test_with_non_type)
I tried looking up what satisfies an is expression but cannot seem to find it in the documentation. It seems like it needs its right-hand operand to be known at compile-time (hoping this is wrong, but it does not seem like I can use a variable), but if so, how else can I achieve the desired effect?
I cant guess the purpose of the function (or the scenario where it would be used, so if you can clarify it would be great). First of all, I don't know if you are passing "types" as arguments. And yes, you need to specify in compile time the right hand argument of the is function.
Meanwhile, if you are passing types, with one change, you can check if the types passed to your function at runtime.
matchesTarget(Type givenType, Type targetType) {
print('${givenType.runtimeType} ${targetType.runtimeType}');
if (givenType == targetType) {
return givenType;
}
return null;
}
main(){
var a = int; //this is a Type
var b = String; //this is also a Type
print(matchesTarget(a,b)); //You are passing different Types, so it will return null
var c = int; //this is also a Type
print(matchesTarget(a,c)); //You are passing same Types, so it will return int
}
But if you are passing variables, the solution is pretty similar:
matchesTarget(givenVar, targetVar) {
print('${givenVar.runtimeType} ${targetVar.runtimeType}');
if (givenVar.runtimeType == targetVar.runtimeType) {
return givenVar.runtimeType;
}
return null;
}
main(){
var a = 10; //this is a variable (int)
var b = "hello"; //this is also a variable (String)
print(matchesTarget(a,b)); //this will return null
var c = 12; //this is also a variable (int)
print(matchesTarget(a,c)); //this will return int
}
The Final Answer
matchesTarget(givenVar, targetType) {
print('${givenVar.runtimeType} ${targetType}');
if (givenVar.runtimeType == targetType) {
return givenVar;
}
return null;
}
main(){
var a = 10; //this is a variable (int)
var b = String; //this is a type (String)
print(matchesTarget(a,b)); //this will return null because 'a' isnt a String
var c = int; //this is also a type (int)
print(matchesTarget(a,c)); //this will return the value of 'a' (10)
}
The as, is, and is! operators are handy for checking types at runtime.
The is operator in Dart can be only used for type checking and not checking if two values are equal.
The result of obj is T is true if obj implements the interface specified by T. For example, obj is Object is always true.
See the below code for an example of how to use the is operator
if (emp is Person) {
// Type check
emp.firstName = 'Bob';
}
Even the error message that you're getting says that
The name 'targetType' isn't a type and can't be used in an 'is'
expression.
So the bottomline is that you can use is only for checking if a variable or value belongs to a particular data type.
For checking equality, you can use the == operator if comparing primitive types, or write your own method for comparing the values. Hope this helps!

How to check if value is enum?

I would like to check if a value in dart is an Enum, and if so, serialize it automatically.
My sticking point is how to test if a value is an enum.
This is how I am testing for other types
if (T == int)
val = prefs.getInt(this._key);
else if (T == double)
val = prefs.getDouble(this._key);
else if (T == bool)
val = prefs.getBool(this._key);
else if (T == String)
val = prefs.getString(this._key);
else if ([""] is T)
val = prefs.getStringList(this._key);
but I cannot seem to compare T to an enum
Since all enums have the same methods I was hoping to sense them and handle them accordingly
As of late 2021, all enums extend Enum
You can now finally use is Enum directly:
enum MyEnum {one, two, three}
var x = "a";
var y = MyEnum.one;
print(x is Enum); // false
print(y is Enum); // true
Which also means you can now create extensions for enums:
extension EnumExtension on Enum { ... }
If you need to check is dynamic value enum type. You can use the next approach. The main idea is quite similar to #Oniya Daniel's answer.
enum Fruit {
banana,
apple,
orange,
}
Next method to check isEnum condition
bool isEnum(dynamic data) {
final split = data.toString().split('.');
return split.length > 1 && split[0] == data.runtimeType.toString();
}
Test result below
test('check enum runtime', () {
expect(isEnum(Fruit.banana), true);
expect(isEnum(null), false);
expect(isEnum(''), false);
expect(isEnum('banana'), false);
});
P.S.: to get enum String value good to use describeEnum(<enum_value>) from the package:flutter/foundation.dart
I don't have enough reputation to comment, or I would have added a statement to the answer by #Dmitry Puzak. In Dmitry's method, if data is passed as the String "String.3.0.1", for instance, the method will incorrectly identify the parameter as an enum. The flutter-provided method, describeEnum, attempts to check that it's parameter is an enum and throws an exception if it's not, but in my experience the exception isn't always thrown when the parameter to describeEnum is a String value containing dots.
For a project I'm working, I modified Dmitry's isEnum method to the following, adding the first if block inside the method:
bool isEnum(dynamic data) {
if (data.runtimeType == "".runtimeType) {
return false;
}
final split = data.toString().split('.');
return split.length > 1 && split[0] == data.runtimeType.toString();
}
This makes sure to return false for any String parameter.
I can't offhand think of any other instance where the runtime type of a variable could possibly match the first part of the split done on the toString() return value.
Convert the enum to a list and check if the list contains the value you intend to check.
enum ObjectType {
TypeA, TypeB
}
// checking against enum values
print(ObjectType.values.contains(ObjectType.TypeA)); // true
print(ObjectType.values.contains(ObjectType.TypeB)); // true
// checking against string value
print(ObjectType.values.contains("ObjectType.TypeA")); // false
// checking against boolean
print(ObjectType.values.contains(false)); // false
// checking against int
print(ObjectType.values.contains(234)); // false
// checking against double
print(ObjectType.values.contains(2.345)); // false

Prove String is referene type in C#

While I know string is reference type, but i could now prove it. because if I take variable test1 as string and assign some value then take other variable naming test2 and assign test2 with test1 variable. so if string is reference type then address of variable test1 will be assign to variable test2. so if i assign some value in tet2 variable which will be reflected in variable test1, but it's not happened.
other one example is if we pass two string variable in function and change value in this function will reflect in calling function, but it's not happen, please see example:-
and give me example by which i can prove that string is reference type. but behavior is different in both case class object and string variable please see again this example. I have edited
private void button1_Click(object sender, EventArgs e)
{
string test1 = string.Empty;
string test2;
String test3 = new String(new char[10]);
test1 = "hemant";
test2 = test1;
test2 = "Soni";
//becuase if string is reference type then after asign value "soni"
// in test2, test1 also show value "soni" instead of value "hemant"
Console.WriteLine("test1:" + test1); // but displaying "hemant", while shoul display "soni"
Console.WriteLine("test2:" + test2); // while displaying "soni"
test3 = "soni";
// if string is reference type then after calling this function
//value of variables test1 and test3 should be changed.
testfn(test1, test3);
Console.WriteLine("test1:" + test1);// but stile displaying "hemant" instead of "hemant New"
Console.WriteLine("test3:" + test3);// but stile displaying "soni" instead of "soni New"
// should be true, because if string reference type then address of both variable should be same.
bool check = test1 == test2;
clsTest obj = new clsTest();
obj.x1 = "Hemant";
obj.x2 = "Soni";
Console.WriteLine("obj.x1:" + obj.x1); //"Hemant";
Console.WriteLine("obj.x2:" + obj.x2);//"Soni";
callFn(obj);
//after calling value has been changed of this object, but in string type its not happed like this
Console.WriteLine("obj.x1:" + obj.x1); //"Hemant New";
Console.WriteLine("obj.x2:" + obj.x2);//"Soni New";
}
public class clsTest
{
public string x1;
public string x2;
}
void callFn(clsTest obj)
{
obj.x1 = "Hemant New";
obj.x2 = "Soni New";
}
void testfn(string x, String y)
{
x = "Hemant New";
y = "Soni New";
}
String is a reference type but it is also immutable. Meaning, you cannot change the value of the string object, only replace it with a reference to another string. Thus when you pass the string into the function and you are assigning the parameter you are only changing the reference of the parameter of x not changing the value at x. To change the reference at x you must use the ref or out keyword on the parameter. This is also true of any kind of object in C#.
class Example {
public string Value;
}
void Foo(Example x, ref Example y) {
x.Value = "mutated"; // mutating the reference
x = new Example { Value = "new reference" }; // only changes local variable
y.Value = "mutated"; // mutating the reference
y = new Example { Value = "new reference" }; // changes the references y is pointing to
}
var x = new Example { Value = "x" };
var y = new Example { Value = "y" };
Foo(x, ref y);
Console.WriteLine(x.Value); // mutated
Console.WriteLine(y.Value); // new reference
But since string is immutable (it cannot be mutated) the only way to change values passed in as parameters is by using the ref or out keywords.
Add the ref keyword to testfn.
void testfn(ref string x, ref String y)
This will reference the object directly.
MSDN ref page

Resources