You change extends to implements, and the Dart analyzer reports Missing concrete implementation of 'Label.render'. But Label clearly has that method. The method has not vanished; the way your class gets its implementation has changed.
Why can extends reuse the parent method?
Consider a Label that wraps a message in square brackets. InheritedLabel does not write its own render method.
class Label {
String render(String text) => '[$text]';
}
class InheritedLabel extends Label {}
void main() {
print(InheritedLabel().render('ready')); // [ready]
}extends makes InheritedLabel a subclass of Label. It can call the implementation supplied by its parent even without declaring render again. This is inheritance of behavior, not merely agreement to expose a method with the same name.
Why does implements produce an analyzer error?
Change the second class to this, keeping the earlier Label declaration:
class BrokenLabel implements Label {}dart analyze reports:
Missing concrete implementation of 'Label.render'.implements promises to provide the members in Label's interface. It does not inherit the existing Label.render body, => '[$text]'. A concrete BrokenLabel must therefore provide render itself. The Dart class documentation describes implements as supporting another class's API without inheriting its implementation.
Provide your own method when implementing the interface
The inherited method prints [ready]. A class implementing the same method contract can provide its own body and print ready instead.
This complete example can be saved as one Dart file and run:
class Label {
String render(String text) => '[$text]';
}
class InheritedLabel extends Label {}
class PlainLabel implements Label {
@override
String render(String text) => text;
}
void main() {
print(InheritedLabel().render('ready'));
print(PlainLabel().render('ready'));
}[ready]
readyBoth objects respond to render, but their results differ. InheritedLabel uses its parent's bracketed implementation. PlainLabel satisfies the same method signature with its own body. @override makes the intention visible; the analyzer checks whether required interface members are actually implemented.
When should you choose extends or implements?
Use extends when you want to reuse the parent's behavior. Use implements when you need the same API with a separate implementation. Here inheritance is simple when brackets are wanted; an implementation is clearer when output rules differ.
Maintenance also differs. Changing the body of Label.render can change a child that inherits it. Adding a required member to the interface means implementers must provide that member. Decide whether you want shared behavior or different behaviors behind the same type. This example compares ordinary class declarations without additional class modifiers.
Key takeaways
extends inherits the implementation of Label.render; implements adopts only the method contract, so a concrete implementing class must write the method. For a Missing concrete implementation error, check whether the class inherits from its parent or only implements its interface.

