Reputation: 1663
Given these two simple design patterns for static values, what are the implications of each of them? Are they identical in performance and memory usage in Dart/Flutter applications when accessing their members?
MyStringsGetters
const strings = MyStringsGetters();
class MyStringsGetters {
const MyStringsGetters();
get helloWorld => 'Hello, World';
}
MyStringsMembers
const strings = MyStringsMembers();
class MyStringsMembers {
const MyStringsMembers();
static const helloWorld = 'Hello, World';
}
Upvotes: 3
Views: 705
Reputation: 483
Example A will be more inefficient. Getters are essentially methods that are called at run time and their response is not cached. Yes, the class instance is const
and will be stored in memory only once, but the getter will essentially create a new memory address every time you call it.
I would suggest going with Example B.
Here is my proof. I built a dummy app that renders 100 Text instances that display the Hello World string using both examples that you shared and here are the results:
You can clearly see the memory allocated is much smaller in Example B
and the main reason is that the getter will allocate new memory addresses.
You can also use the Memory DevTool to play with these kind of questions. Here is the code that I used:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
const strings = MyStringsMembers();
class MyStringsMembers {
const MyStringsMembers();
static const helloWorld = 'Hello, World';
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: MyStringsMembers.helloWorld,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<Widget> _widgets() {
List<Widget> result = [];
for (var i = 0; i < 10000; i++) {
result.add(Text(MyStringsMembers.helloWorld));
}
return result;
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center, children: _widgets()),
),
);
}
}
If you are interested in more tips on how to improve the performance of your Flutter app, I wrote an article here.
Is this documented somewhere?
I tried looking through the documentation and couldn't find much on this. The closest info that I found in the Dart Programming Language Specification book page 37.
Getters are functions (9) that are used to retrieve the values of object properties.
Given that you are not storing the value of the string as an object property and the getter is essentially just a helper function that does what you specify, it will end up allocating memory every time is called. "Hello world"
is essentially saying create a new string in memory with this content.
Upvotes: 4
Reputation: 5049
Kind of. Example A, getter will be called on object of MyStringsGetters. i.e.
strings.helloWorld
But example B, helloWorld will be called on MyStringsMembers. i.e. you can't call strings.helloWorld
like in Example A.
You should use Example B version if same value is retuned from a getter in a class irrespective of instance (hence the static
keyword).
But Example A can be modified to
void main(){
print(MyClass("Hello World").value);
print(MyClass("Thank you").value);
}
class MyClass {
final String _value;
const MyClass(String value) : _value=value;
String get value => _value;
}
You will get output
Hello World
Thank you
MyClass is still a const
which means all the possible values of MyClass will be known as compile time.
Upvotes: 1