Coder Social home page Coder Social logo

Comments (25)

DisDis avatar DisDis commented on May 28, 2024 7

In our big project. Main priority is code support. We have 'toName', 'toSymbol' an analog of nameof. It is made using a transformer and the special code for run vm test.
We very often use this for:
Deserialization/Serialization, Angular.Dart, noSuchMethod

// Deserialization
class AccountDeserializer extends EntityDeserializer {
  static final _rightsSymbol = toSymbol((Account o) => o.rights);
  static final List<DeserializeField> _fields = [
    new DeserializeSingleField("isOwner", toSymbol((Account o) => o.isOwner)),
    new DeserializeSingleField("isAdmin", toSymbol((Account o) => o.isAdmin)),
....

// Angular
ngOnChanges(Map<String, SimpleChange> changes){
   if (changes.containsKey(nameof(field)) ....
}

Interface

toSymbols([o.field1, o.field2]);// => [#field1,#field2]
toSymbol(o.field1);// => #field1
toSymbols((Task o)=>[o.field1, o.field2]);// => [#field1,#field2]
toSymbol((Task o)=>o.field1);// => #field1

toNames([o.field1, o.field2]);// => ['field1','field2']
toName(o.field1);// => 'field1'
toNames((Task o)=>[o.field1, o.field2]);// => ['field1','field2']
toName((Task o)=>o.field1);// => 'field1'

All this is directed to ensure that the code is connected at all parts. Developers should receive a real "Find usages". Developers should safely refactor the code. Also in our company, literals are forbidden. Since literals are potential errors.
Now the transformer has become a problem, as we move to build. 'nameof' solves the problems at the language level.

@matanlurey @lrhn

from language.

lrhn avatar lrhn commented on May 28, 2024 5

You can use it in noSuchMethod.
It might even help you with the named arguments of Function.apply, but only if you are somehow allowed to denote a named parameter of a function signature.

It's a good idea. The current symbol literals are stupid - they're basically shorthands for strings, there is no relation to the identifier you actually want to match. That makes typos hard to detect and refactoring impossible to automate. Example:

abstract class Foo {
  int bar();
}
class MockFoo implements Foo {
  noSuchMethod(i) {
    if (i.memberName == #baar) return 42;   // Whoops
    return super.noSuchMethod(i);
  }
}

I wouldn't use a macro like nameof (Dart doesn't have precompiler macros otherwise), but I would definitely like something that takes qualified name in scope and provides the symbol for that name. It should be recognizable in renaming and other refactorings.

We can't use #foo since that already works for things that are not in scope.
So, for the giggles, let's try ##foo. It would have a grammar like a symbol, but be interpreted differently:

import "self.dart" as self;
abstract class C {
  static foo({bar});
  baz({qux});
  get toto;
}
main() {
  var c = ##C;
  var cFoo = ##C.foo;
  var cFooBar = ##C.foo.bar; // maybe.
  var cFooBar2 = ##self.C.foo.bar;
  print(identical(cFooBar, cFooBar2));  // true, yey!
  // var wrong = ##C.biff;  // Invalid, no biff declared in C.
}

and

class MockFoo implements Foo {
  noSuchMethod(i) {
    if (i.memberName == ##Foo.bar) return 42;  
    // or just `== ##bar`, using the dynamic this-scope since "bar" isn't otherwise in scope.
    return super.noSuchMethod(i);
  }
}

Other possible, but probably too odd, syntaxes: #foo.bar#, #:foo.bar, #!foo.bar ...
No great syntax so far :(

See also #30518,

from language.

ranquild avatar ranquild commented on May 28, 2024 3

@matanlurey if (changes.containsKey(nameof(field)) ....

from language.

jodinathan avatar jodinathan commented on May 28, 2024 1

this would help me so much.

All my models are like:

class SomeClass extends Model {
  int _myProp;

  int get myProp => _myProp;
  set myProp(int x) {
    this.modified('myProp', _myProp, _myProp = x);
  }
}

would be amazing to do something like:

class SomeClass extends Model {
  int _myProp;

  set myProp(int x) {
    this.modified(##SomeClass.myProp, _myProp, _myProp = x);
    // becomes
    this.modified('myProp', _myProp, _myProp = x);
  }
}

from language.

tomdowdell avatar tomdowdell commented on May 28, 2024 1

The C# nameof() operator is definitely useful for those of us who create professional developer tools. Please add this feature!

The following example is not trying to prove the benefit, it just shows a use case for a minimal implementation of nameof(member-field) that would satisfy my primary needs:

class Ant {
  String firstName;

  Bat() {
  var s = nameof(firstName);
  }
}

I'm trying to create a library for Flutter. Without nameof(member-field) users will have to hard-code dozens to hundreds of field names that, obviously, will need to be updated manually should fields name actually change versus having it update automatically thanks to the magic of an IDE member renaming feature.

from language.

festelo avatar festelo commented on May 28, 2024 1

There can be a problem with code minification. Imagine we have client-server app, client and server are both on dart. We also have some shared code that used by both.

Shared code:

class SomeModel {
    final name;
    
    SomeModel.fromMap(map):
        name = map[nameof(name)];

    toMap() => {
        nameof(name): name
    };
}

Flutter web application built in release will not be able to deserialize code serialized by Server and vice versa.

Client's toMap will produce map

{ "mF": "some name" }

Server's toMap will produce map

{"name": "some name"}

Because type and field names are minified in flutter web, but not minified in server. Even when the actual code is the same.
Should nameof(*) return real member name or member name from source code?

Code like (SomeModel).toString() currently returns different values on flutter web debug and release.

from language.

esDotDev avatar esDotDev commented on May 28, 2024 1

Right, thanks for the correction. The longer method is still preferred as it's avoids the magic strings and lets the compiler keep the names in sync.

from language.

matanlurey avatar matanlurey commented on May 28, 2024

Considering that you can't use this information (i.e. there is no reflective support), what would this accomplish?

from language.

matanlurey avatar matanlurey commented on May 28, 2024

At least for that particular API, we decided it was probably wrong.

I don't know if I'd push for a language feature to fix the API we created (personally).

from language.

lrhn avatar lrhn commented on May 28, 2024

There are many places where using symbols is just making life harder for yourself, but they are still useful in a few places (noSuchMethod is the primary culpit). It is annoying that you can't link a reference to a particular variable or declaration, it means that you don't even detect typos and refactorings won't work. Even DartDoc does better than that.

The language feature by itself makes sense. Whether it carries its own weight, and whether it is worth prioritizing over other language features, are different questions.

from language.

kevmoo avatar kevmoo commented on May 28, 2024

@lrhn @munificent @leafpetersen – is this more of a language request?

I've been hitting this a lot in the last few days – would make a lot of folks very happy!

from language.

munificent avatar munificent commented on May 28, 2024

Yes, this sounds like a language request to me. Want to move it over to the language repo?

from language.

kevmoo avatar kevmoo commented on May 28, 2024

Yes, this sounds like a language request to me. Want to move it over to the language repo?

Sure!

from language.

eernstg avatar eernstg commented on May 28, 2024

I guess the desired guarantee here (cf. the C# nameof) would be that a given symbol corresponding to a single identifier or operator does in fact exist as the name of a declared member of some type.

If we make this a built-in property of certain symbols (say, by spelling them as ##foo rather than #foo), it is not immediately obvious to me how we could support specification of that type. We could of course just require that there is some type, somewhere, that has a member called foo, and if there is no such type then ##foo is a compile-time error.

But that's a rather weak guarantee. So maybe the following would be more practical:

main() {
  const s1 = memberSymbol<A>(#foo); // OK, s1 gets the value `#foo`.
  var s2 = memberSymbol<B>(#bar); // OK, memberSymbol(...) is always const.
  var s2 = memberSymbol<B>(#foo); // OK, `foo` is in the interface of `B`.
  var s3 = memberSymbol<B>(#baz, staticMember: true); // OK.
  var s4 = memberSymbol<A>(#qux); // Compile-time error.
  memberSymbol(#s1); // Error, refuses to infer a type argument, and `s1` not a member.
}

abstract class A {
  foo();
  Symbol get test => memberSymbol(#foo); // OK, type argument `A` inferred.
}

class B extends /*or implements, or mixes in*/ A {
  int get bar => 42;
  static void baz() {}
}

This would allow implementations of noSuchMethod to use a plain memberSymbol and rely on inference (the desired and inferred type argument is always the enclosing class), and all other usages could give an explicit type argument if needed.

The memberSymbol "function" would be special in that an application of it is a constant expression, and its argument must (of course) be a constant expression, and the evaluation just returns its argument if the given type does have a member with that name; with an argument which is not a member, like memberSymbol<A>(#qux) above, the expression is a compile-time error.

We could extend this idea slightly to allow for an optional argument staticMember which would allow us to check that a given symbol is the name of a static member of the given type (which must then be a class type, of course); we could also just omit support for that kind of check, or we could allow it without any special marker (so we'd simply use memberSymbol<B>(baz)).

We could of course also consider checking other symbols at compile-time (classSymbol(#String) ok, classSymbol(#NoSuchClass) compile-time error), and we might be able to offer these services in a more unified manner (using a single isSymbol with various optional arguments), but the main point is that we are likely to want a little bit more than just "this symbol corresponds to a declared name in this program".

from language.

machinescream avatar machinescream commented on May 28, 2024

Any news guys?

from language.

leafpetersen avatar leafpetersen commented on May 28, 2024

Any news guys?

I'd say that this request is still open, and seems to have some level of support, but there are a lot of higher priority things occupying both the language team and the implementation teams right now, so I don't expect this to bubble to the top of the queue in the short term.

from language.

raulchall avatar raulchall commented on May 28, 2024

+1 to this, just couple days into Flutter + Firestore started looking for this

from language.

rrousselGit avatar rrousselGit commented on May 28, 2024

Maybe an alternate solution is to create a new lint rule that warns when a symbol's name doesn't match any variable available?

from language.

zs-dima avatar zs-dima commented on May 28, 2024

nameof(obj.propertyName); // 'propertyName' - this feature more then welcome:

map[nameof(obj.propertyName)] = SomeData();
* * *
final data = map[nameof(obj.propertyName)];

from language.

esDotDev avatar esDotDev commented on May 28, 2024

Fwiw, this would be nice for the new Restorable API in flutter, so we don't need to constantly repeat ourselves:
"someInt" is redundant here almost all the time:

RestorableInt someInt = RestorableInt(0);
...
@override
  void restoreState(RestorationBucket oldBucket, bool initialRestore) {
    registerForRestoration(someInt, "someInt");
   //registerForRestoration(someInt); // This should be enough, and is less prone to bugs
  }

Would be nice to just pass null, and have it internally use nameof(). Also prevents magic string bugs, so its actually better and more robust this way, and works better with refactoring.

The id in this case is a string that is supposed to be unique within the scope of a class, which is of course accomplished by just using it's property name;

from language.

esDotDev avatar esDotDev commented on May 28, 2024

Another real world use case we came across, We're trying to come up with some concise method of re-using state in a StatelessWidget in Flutter.

Landed on an API that needs a unique-in-scope string, very similar to Restoration:

build(){
  StatefulAnimation anim1 = getProp("anim1", create: (){ ... })
  ...
}

I think anim1 = getProp(nameOf(anim1), ...) would be preferred here.

from language.

bannmann avatar bannmann commented on May 28, 2024

Another use case which was not yet mentioned is throwing exceptions that include the parameter name:

set foo(String value) {
  _foo = ArgumentError.checkNotNull(value, nameof(value));
}

void bar(String data) {
  if (!isValid(data)) {
    throw ArgumentError.value(data, nameof(data));
  }
  ...
}

void quux(String data) {
  if (data == null) {
    throw ArgumentError.notNull(nameof(data));
  }
  ...
}

from language.

pchasco avatar pchasco commented on May 28, 2024

There can be a problem with code minification. Imagine we have client-server app, client and server are both on dart. We also have some shared code that used by both.

Wouldn't nameof() be resolved before any minification, so property names would still match the keys in the serialized data?

from language.

shtse8 avatar shtse8 commented on May 28, 2024

There can be a problem with code minification. Imagine we have client-server app, client and server are both on dart. We also have some shared code that used by both.

Wouldn't nameof() be resolved before any minification, so property names would still match the keys in the serialized data?

before minification would make it to be a const string, minification wouldn't take affect on that.

from language.

codelovercc avatar codelovercc commented on May 28, 2024

A nameof expression produces the name of a variable, type, or member as the string constant. A nameof expression is evaluated at compile time and has no effect at run time. https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/nameof
This is not about reflection and don't take affect on minification.
In my case, I have various models that use to request to the server, let me say, if a LoginModel has any validation error on the server side, the server will response with json: {"title":"validation error","errors":{"account":["Account is required."],"password":["Passowrd is required"]}}
Here is the dart class model:

class LoginModelProblemDetails {
  final List<String>? account;

  final List<String>? password;

  final List<String>? accountType;

  LoginModelProblemDetails({
    this.account,
    this.password,
    this.accountType,
  });

  bool hasAnyError(){
    return account?.isNotEmpty == true || password?.isNotEmpty == true || accountType?.isNotEmpty == true;
  }
  
  bool hasError(String fieldName){
    switch(fieldName){
      case "account":
        return account?.isNotEmpty == true;
      case "password":
        return password?.isNotEmpty == true;
      case "accountType":
        return accountType?.isNotEmpty == true;
      default:
        return false;
    }
  }

If I can use nameof keyword, that would be

class LoginModelProblemDetails {
  final List<String>? account;

  final List<String>? password;

  final List<String>? accountType;

  LoginModelProblemDetails({
    this.account,
    this.password,
    this.accountType,
  });

  bool hasAnyError(){
    return account?.isNotEmpty == true || password?.isNotEmpty == true || accountType?.isNotEmpty == true;
  }
  
  bool hasError(String fieldName){
    switch(fieldName){
      case nameof(account):
        return account?.isNotEmpty == true;
      case nameof(password):
        return password?.isNotEmpty == true;
      case nameof(accountType):
        return accountType?.isNotEmpty == true;
      default:
        return false;
    }
  }

check it:

final problemDetails = LoginModelProblemDetails.fronJson(jsonDecode('{"title":"validation error","errors":{"account":["Account is required."],"password":["Passowrd is required"]}} '));
print(problemDetails.hasError(nameof(account));

I have a lot of models ModelProblemDetails like, and it aways decode from json that the server responded, my UI layer use method hasError to toggle the validation state that display to user. I need keyword nameof to save my life.

from language.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.