how to enable refactor-rename when symbols are around?

86 views
Skip to first unread message

Seth Ladd

unread,
Sep 4, 2013, 4:55:03 AM9/4/13
to General Dart Discussion, John Messerly
Hi all,

We now have symbols, which are often used to represent names in Dart code, I'm concerned we're losing some tooling ability.

e.g. this is common in Polymer.dart code:

    bindProperty(this, const Symbol('timestamp'),
        () => notifyProperty(this, const Symbol('second')));

The first symbol is the name of a field, the second symbol is the name of a getter. If I rename my field, the symbol is left untouched. And if I misspell the symbol name...

This lies at the intersection of tooling, API design, and maybe language. Do you think we can do better here? Should the API be changed or should the tools help here?

Thanks for your insight,
Seth

Lasse R.H. Nielsen

unread,
Sep 4, 2013, 5:32:23 AM9/4/13
to mi...@dartlang.org
This is not a new problem.

If you have a function like; 

   foo(var bar) {
      notifyProperty(bar.second, bar.timestamp)
   }

and you rename the "second" getter on a class Bar, you won't have any link between "bar.second" and "Bar.second". Symbols are the same, it's the name of an object property without a static way to determine which class the object is.

I don't see a good solution for that, but maybe recognizing #second anywhere in the code when you rename a member called "second" and asking for each one whether it should be changed. I.e., similar to a global replace with a query for each replacement (and an option to replace all).

That could work for both symbols and unanalyzable property accesses.

/L



--
For other discussions, see https://groups.google.com/a/dartlang.org/
 
For HOWTO questions, visit http://stackoverflow.com/tags/dart
 
To file a bug report or feature request, go to http://www.dartbug.com/new

To unsubscribe from this group and stop receiving emails from it, send an email to misc+uns...@dartlang.org.



--
Lasse R.H. Nielsen - l...@google.com  
'Faith without judgement merely degrades the spirit divine'
Google Denmark ApS - Frederiksborggade 20B, 1 sal - 1360 København K - Denmark - CVR nr. 28 86 69 84

Florian Loitsch

unread,
Sep 4, 2013, 7:38:21 AM9/4/13
to General Dart Discussion
On Wed, Sep 4, 2013 at 11:32 AM, Lasse R.H. Nielsen <l...@google.com> wrote:
This is not a new problem.

If you have a function like; 

   foo(var bar) {
      notifyProperty(bar.second, bar.timestamp)
   }

and you rename the "second" getter on a class Bar, you won't have any link between "bar.second" and "Bar.second". Symbols are the same, it's the name of an object property without a static way to determine which class the object is.

I don't see a good solution for that, but maybe recognizing #second anywhere in the code when you rename a member called "second" and asking for each one whether it should be changed. I.e., similar to a global replace with a query for each replacement (and an option to replace all).
Alternatively, we could maybe allow to extract the symbol name of a member: const Symbol.fromMember(Bar.second);
This would also have the advantage of being stable to minifying.
Currently, of course, this is impossible for all kinds of reasons, but if you are actually referring to a member that's probably what you want.

(disclaimer: I have never used symbols or mirrors. So I could be completely off).



--
Give a man a fire and he's warm for the whole day,
but set fire to him and he's warm for the rest of his life. - Terry Pratchett

Lasse R.H. Nielsen

unread,
Sep 4, 2013, 7:59:26 AM9/4/13
to mi...@dartlang.org
With the literal syntax, it would even make sense: #Bar.foo (except that this syntax is reserved for library names). Or  const Symbol("foo", from: Bar) .
/L

Sean Eagan

unread,
Sep 4, 2013, 9:31:20 AM9/4/13
to General Dart Discussion
On Wed, Sep 4, 2013 at 6:59 AM, Lasse R.H. Nielsen <l...@google.com> wrote:
With the literal syntax, it would even make sense: #Bar.foo

Why not:

Bar#
Bar#foo
 
(except that this syntax is reserved for library names).

and libraries could be:

some.library#
some.library#foo

(which seems to solve http://dartbug.com/12586)

Or  const Symbol("foo", from: Bar) .

How about:

const Symbol.fromType(Bar)
const Symbol.fromType(Bar, member: "foo")

const Symbol.fromLibrary("some.lib")
const Symbol.fromLibrary("some.lib", member: "foo")

or combine these into a single constructor:

const Symbol.scoped(Bar)
const Symbol.scoped(Bar, member: "foo")
const Symbol.scoped("some.library")
const Symbol.scoped("some.library", member: "foo")

Erik Grimes

unread,
Sep 4, 2013, 11:04:09 AM9/4/13
to mi...@dartlang.org
+1 

I create symbol constants for everything that is referred to by symbols specifically to support tooling.  It is definitely cumbersome.  It would be awesome if the tools could connect symbol literals with the target of the symbol for things like refactoring, code completion warnings, etc.

Justin Fagnani

unread,
Sep 4, 2013, 11:11:35 AM9/4/13
to General Dart Discussion
I proposed the idea of #Foo.bar when symbol literals were discussed and it wasn't shot-down, but it was decided to look at it later. It may yet happen, but that syntax wouldn't be used everywhere, and we still have refactoring issues with untyped code, so we should still think about something like Lasse's proposal.

Seth Ladd

unread,
Sep 4, 2013, 10:06:59 PM9/4/13
to General Dart Discussion
I'm encouraged that the suggestion for better tooling in the face of symbols wasn't totally shot down. Yay!

This lives at the intersection of tooling and language evolution (and perhaps library evolution). Our bug tracker isn't setup for these kind of broad, cross-concern issues. I've filed https://code.google.com/p/dart/issues/detail?id=13056 to request we improve the state of tooling in the face of symbols. Any suggestion on how to categorize this request?

Justin Fagnani

unread,
Sep 4, 2013, 11:17:30 PM9/4/13
to General Dart Discussion
It's a language issue first, since the spec needs to state something like #Foo.qux and #Bar.qux create the same Symbol instance, with the additional class part there only for tools.

Sean Eagan

unread,
Sep 5, 2013, 10:39:22 AM9/5/13
to General Dart Discussion
On Wed, Sep 4, 2013 at 10:17 PM, Justin Fagnani <justin...@google.com> wrote:
It's a language issue first, since the spec needs to state something like #Foo.qux and #Bar.qux create the same Symbol instance, with the additional class part there only for tools.

The class information will be useful at runtime as well, I wouldn't want to lose it.  Any reflective APIs which don't need the class part could just ignore it.

For example, it would be cool to be able to get a version of an instance method, which adds the instance as the first argument.  Assume I have:

class A {
  String manyParams(String first, String second, [String third = 'third', String fourth = 'fourth']);
}

To get the closurization I want, it would not be DRY at all:

(a, first, second, [third = 'third', fourth = 'fourth']) => a.manyParams(first, second, third, fourth);

I would rather have some reflective API which takes a Symbol and does this for me:

closurize(A#manyParams);

Cheers,
Sean Eagan

Justin Fagnani

unread,
Sep 5, 2013, 11:23:08 AM9/5/13
to General Dart Discussion
I think this would be better covered by a richer mirror API. Something like:

reflect(a)[#manyParams]

Which would be equivalent to reflect(a)[#A.manyParams] if you wanted to make it more tool-friendly.

 
Cheers,
Sean Eagan

Sean Eagan

unread,
Sep 5, 2013, 11:38:37 AM9/5/13
to General Dart Discussion
On Thu, Sep 5, 2013 at 10:23 AM, Justin Fagnani <justin...@google.com> wrote:



On Thu, Sep 5, 2013 at 7:39 AM, Sean Eagan <seane...@gmail.com> wrote:
On Wed, Sep 4, 2013 at 10:17 PM, Justin Fagnani <justin...@google.com> wrote:
It's a language issue first, since the spec needs to state something like #Foo.qux and #Bar.qux create the same Symbol instance, with the additional class part there only for tools.

The class information will be useful at runtime as well, I wouldn't want to lose it.  Any reflective APIs which don't need the class part could just ignore it.

For example, it would be cool to be able to get a version of an instance method, which adds the instance as the first argument.  Assume I have:

class A {
  String manyParams(String first, String second, [String third = 'third', String fourth = 'fourth']);
}

To get the closurization I want, it would not be DRY at all:

(a, first, second, [third = 'third', fourth = 'fourth']) => a.manyParams(first, second, third, fourth);

I would rather have some reflective API which takes a Symbol and does this for me:

closurize(A#manyParams);


I think this would be better covered by a richer mirror API. Something like:

reflect(a)[#manyParams]

Which would be equivalent to reflect(a)[#A.manyParams] if you wanted to make it more tool-friendly.

In the use case I'm describing, you won't have an `a` instance when doing the closurization, so your suggestion would be more like:

reflectClass(A)[A#manyParams]

which is not terrible, but still duplicates the class name, which means it's likely people will just write:

reflectClass(A)[#manyParams]

and thus miss out on the tooling support.

Cheers,
Sean Eagan
Reply all
Reply to author
Forward
0 new messages