Comments (25)
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.
from language.
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.
@matanlurey if (changes.containsKey(nameof(field)) ...
.
from language.
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.
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.
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.
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.
Considering that you can't use this information (i.e. there is no reflective support), what would this accomplish?
from language.
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.
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.
@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.
Yes, this sounds like a language request to me. Want to move it over to the language repo?
from language.
Yes, this sounds like a language request to me. Want to move it over to the language repo?
Sure!
from language.
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.
Any news guys?
from language.
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.
+1 to this, just couple days into Flutter + Firestore started looking for this
from language.
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.
nameof(obj.propertyName); // 'propertyName'
- this feature more then welcome:
map[nameof(obj.propertyName)] = SomeData();
* * *
final data = map[nameof(obj.propertyName)];
from language.
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.
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.
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.
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.
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.
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)
- Assignability of generic type `Never` HOT 6
- Support trailing commas in `<catchPart>` HOT 5
- Allow pattern matching on error handling
- Make sealed type hierarchies more pleasurable to use HOT 3
- Require augmentation libraries to link to their main library, not the parent HOT 9
- Commits in the language repository fail because of analyzer failure in macro_proposal HOT 1
- CSS-like inheritance of certain properties? HOT 9
- Late parameters, late-init-query operator, parameter element HOT 11
- More user-definable unary operators? HOT 4
- `switch` should understand that when a field of an object with a parameter type T that shares T with one of its fields and the field is exhaustively checked it may be promoted HOT 1
- `switch` should be considered exhaustive when an object of type S with a type parameter T shares T with one of its fields with type U, which is a sealed class, and has T checked against all possible types for U HOT 4
- Improved null-aware parsing HOT 2
- Augmentation of extensions seems to be difficult HOT 3
- What does `augment` mean when applied to an `enum` value? HOT 1
- Augmentations should specify allowed partial declarations.
- Incorrect difference.inDays value after time change HOT 2
- Extension types should implements record types HOT 1
- Change more elements of augmenting type declarations to be optional? HOT 1
- Improve inference of function literal parameter types HOT 5
- Inference of the declared type in a for-in statement differs from local variable declarations HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from language.