What is Symbol in Dart?
#dart#symbol#reflection#mirrors#identifier
Answer
Overview
A
text
Symboltext
dart:mirrorsCreating Symbols
There are two ways to create a Symbol:
dartvoid main() { // 1. Symbol literal (compile-time constant) const symbol1 = #myVariable; const symbol2 = #MyClass; const symbol3 = #myMethod; const symbol4 = #dart.core; // Library name // 2. Symbol constructor (runtime) final symbol5 = Symbol('myVariable'); // Both are equivalent print(#myVariable == Symbol('myVariable')); // true }
Why Symbols Exist
The Minification Problem
When Dart code is compiled for the web, identifiers are minified (shortened) to reduce file size. Strings would not survive this process, but Symbols do.
dart// In source code: class UserService { void fetchUser() {} } // After minification: class a { void b() {} } // String 'fetchUser' ❌ — broken after minification // Symbol #fetchUser ✅ — minified along with the code
Symbols get minified together with the code they reference, so they always refer to the correct identifier — even after minification.
Symbols with Reflection (dart:mirrors)
The primary use case for Symbols is with Dart's mirror-based reflection system:
dartimport 'dart:mirrors'; class User { String name; int age; User(this.name, this.age); String greet() => 'Hello, I am $name'; } void main() { final user = User('Alice', 30); // Reflect on the instance final mirror = reflect(user); // Access field using Symbol final nameMirror = mirror.getField(#name); print(nameMirror.reflectee); // 'Alice' // Set field using Symbol mirror.setField(#name, 'Bob'); print(user.name); // 'Bob' // Invoke method using Symbol final result = mirror.invoke(#greet, []); print(result.reflectee); // 'Hello, I am Bob' // Inspect class members final classMirror = reflectClass(User); classMirror.declarations.forEach((symbol, declaration) { print(MirrorSystem.getName(symbol)); // name, age, greet, User }); }
Symbol Properties and Methods
dartvoid main() { const sym = #myMethod; // Symbols are constants — can be used in switch/case switch (sym) { case #myMethod: print('Matched myMethod'); case #otherMethod: print('Matched otherMethod'); } // Symbols support equality print(#myMethod == #myMethod); // true print(#myMethod == #otherMethod); // false print(#myMethod == Symbol('myMethod')); // true // Symbols can be used as Map keys final metadata = <Symbol, String>{ #name: 'Alice', #role: 'Developer', }; print(metadata[#name]); // 'Alice' }
Converting Between Symbol and String
dartimport 'dart:mirrors'; void main() { // Symbol → String (requires dart:mirrors) const sym = #myVariable; final name = MirrorSystem.getName(sym); print(name); // 'myVariable' // String → Symbol final sym2 = Symbol('myVariable'); print(sym2); // Symbol("myVariable") }
Practical Use Cases
1. No-Such-Method Forwarding
dartclass DynamicProxy { dynamic noSuchMethod(Invocation invocation) { final methodName = invocation.memberName; // This is a Symbol print('Called: $methodName'); print('Positional args: ${invocation.positionalArguments}'); print('Named args: ${invocation.namedArguments}'); return null; } } void main() { dynamic proxy = DynamicProxy(); proxy.anyMethod('hello', count: 5); // Called: Symbol("anyMethod") // Positional args: [hello] // Named args: {Symbol("count"): 5} }
2. Constant Map Keys
dartconst permissions = <Symbol, bool>{ #read: true, #write: false, #delete: false, }; bool hasPermission(Symbol action) => permissions[action] ?? false; void main() { print(hasPermission(#read)); // true print(hasPermission(#delete)); // false }
Important Limitations
| Limitation | Details |
|---|---|
| No text | Flutter uses AOT compilation, which disables text |
| Reflection alternatives | Use code generation ( text text |
| Limited toString | text text text |
| Cannot extract name without mirrors | text text |
Symbol in Flutter (Without Mirrors)
Since
text
dart:mirrorsdart// noSuchMethod still uses Symbols in Flutter class SafeMap { final Map<String, dynamic> _data; SafeMap(this._data); dynamic noSuchMethod(Invocation invocation) { final key = invocation.memberName.toString() .replaceAll('Symbol("', '') .replaceAll('")', ''); return _data[key]; } }
Key Insight:
is a compile-time constant representation of a Dart identifier. It was designed for reflection (textSymbol) and survives minification. In Flutter, direct Symbol usage is rare becausetextdart:mirrorsis disabled — but the concept is important for understanding Dart's type system andtextdart:mirrorsforwarding.textnoSuchMethod