I have a file in the app folder named constants.dart.
An example of a constant is
const String name = "Daniel";
I want to be able to use the const variables from the file by typing Constant.name.
What's the difference between making a class named Constant and putting public static variables or by importing my constants file with as constant;.
Is there a third option?
What if it's a utils file and I have methods with no side effects?
Thanks!
The officially recommended style is to use top-level constants, not have a class containing them.
That allows users to import them with any prefix (not just Constant) or even without a prefix, if they really want to.
Using a class as container is arbitrary. You can use a class, a mixin or an extension declaration to declare constants. All three introduce a static namespace on top of what they otherwise do, and if the static namespace is all you care about, you can use any of them.
To be honest, if all I really want is a namespace, I'd probably do:
// Namespace containing utility functions!
extension MyConstants on Never {
static int foo() => 42;
static const int = 10;
}
and not use a class. That way, it won't introduce a type that is never used for anything anyway.
Or really, I'd follow the style guide and do top-level declarations instead.
Related
I need a workaround or idiomatic way to access the static members defined in some type from a generic context.
Example:
enum E { first, second, third }
// no direct syntax to constrain to enum types
class EnumKeyList<TEnum> {
List<Object> _values;
// unable to access static member
EnumKeyList() : _values = List.filled(TEnum.values.length, Object());
// unable to access instance member
Object operator [](TEnum entry) => _values[entry.index];
}
Usage:
final list = EnumKeyList<E>(); // E.values.length would provide implicit fixed-size list instantiation
list[E.first] = 5; // can use enumeration entries as keys
I want to avoid the overhead of Map (hashing and additional memory). The real use case must index into the list in tight loops.
Having a fixed set of named keys is a useful requirement, but the example EnumKeyList should work with any generic type argument that provides an enumeration like interface.
Using enumerations provides the shortest way to declare valid 0-indexed keys and the count of the amount of entries through an enumeration's static values member.
Swift enumerations and protocols allow for static members. C# has constraints for enumeration types. C++ generics dwarf everything. Is there a simple way to achieve this in Dart?
I realize that I can declare my own class instead of an enumeration, but then I lose the implicitly generated members (having to manually assign a value to each constant in the class (bad for maintenance)) and I still can't provide access to a static member from the generic context.
See here for examples of how unmaintainable this is:
abstract class Enum {
final int rawValue;
const Enum(this.rawValue) : assert(rawValue >= 0);
// don't bother with a static 'values' member
}
class E extends Enum {
const E(int rawValue) : super(rawValue);
static const first = E(0);
static const second = E(1);
static const third = E(1); // repeated values
static const List<E> values = <E>[first, second]; // missed one
}
You cannot access static members through type variables.
Dart static members are really just declared in the namespace of the corresponding class/mixin/extension declaration, they are not part of the type. Type variables hold types, not declarations.
There is no idiomatic workaround.
You have to figure out which operations you need your class to support, then you can introduce a strategy object representing the class, and pass that to the function instead of (or alongside) the type argument.
In this case, you probably want the EnumKeyList constructor to take the list of values as an argument, so:
EnumKeyList(List<T> values) : _values = List.unmodifiable(values);
The workaround, in general, is to pass the values you'd want to read from a static member directly to the function needing them, along with the type.
You can't access them using the type alone.
The "cannot access index" problem could be fixed by the language adding an interface to all enums, like abstract class Enum { int get index; } and make all enum classes implement that interface.
There is no easy way to allow access to the values knowing only the type.
It might be possible to do something magical in the compiler and platform libraries, but it won't extend to user-written enums like this, and no viable way to emulate it.
I have a class that extends another. The parent class is not intended to be used directly by the API rather it implements basic methods that are helpers for child classes.
When I use the child class in a program I can see all method from said class but also the one from the parent class that are not intended to be called directly, they exist to be called by the methods of the child class.
I tried to make parents method private. This would work I believe as long as parent and child are declared in the same library. But I have an issue with the "library" notion. I understand part/part of are somewhat depreciated, and I want the parent class to be in a specific file. I can't figure a way to do it with import/export.
Is there a way to either hide a public method from the parent class from all child classes usage or to make a private method from the parent class callable from all child classes ?
Best regards ;
Exemple:
myLib.dart
export mainClass.dart;
mainClass.dar
import baseClass.dart;
class MainClass extends BaseClass {
publicFunc() => ... //Can't call _hiddenFunc, can call wantToHideFunc()
}
In a second file (for code reusability purposes)
class MainClass extends BaseClass {
_hiddenFunc() => ...
wantToHideFunc() => ...
}
Using myLib public API
import myLib.dart
main() {
class = Class();
class.publicFunc(); //Intended
class.wantToHideFunc() //Wants to avoid...
}
Dart does not have protected access like Java or C#.
You can't hide a public member, you can't access a private member from a different library, and there is no third option.
It sounds like you want members of the superclass which can be invoked only from subclasses, not from outside of the object. That's what's called protected in, e.g., Java, and Dart does not have anything similar to that.
The only level of privacy in Dart is library-private, which is chosen by starting the name with a _.
The reason that Dart has this design is that it was originally a very dynamic language. You can preform "dynamic invocations" on a value with static type dynamic, say dynVal.foo(42) and it will call the method of that name.
To make a name unreachable, it needed to be safe from dynamic invocation as well. Because of that, Dart privacy does not care where the code doing the invocation is, it only cares whether you know the name - and library private names are considered different names depending on which library they're from.
Using part is not discouraged for situations where it actually serves a purpose. If you can put the part into a library of its own, that's better because it allows it to have its own privacy and imports, but if you need the classes to share privacy, using part files to split up a large file is perfectly reasonable. It's a tool, there is nothing wrong with using it when it's the right tool for the job. A library is often a better tool for modularity, but not always.
Now, there is a hack you can use:
// Declare the base and provide extensions for "protected" members:
abstract class Base {
int get _someHiddenStuff => 42;
int get somePublicStuff => 37;
}
extension ProtectedBase on Base {
int get someHiddenStuff => _someHiddenStuff;
}
Then import that in another library and do:
import "base.dart";
export "base.dart" hide ProtectedBase;
class SubClass extends Base {
int doSomething => someHiddenStuff + somePublicStuff;
}
Then anyone importing "subclass.dart" will also get a version of Base, but they won't get the ProtectedBase extensions. Hiding the extensions from your package's public API will allow yourself to use it, but prevent your package's users from seeing the helper extensions.
(This is likely highly over-engineered, but it's an option. It's the evolution of the hack of having static/top-level helper functions that you don't export.)
I'm trying to create a static extension method on one of my classes (which is autogenerated, so I can't easily modify it). According to the docs, this should be possible:
Extensions can also have static fields and static helper methods.
Yet even this small example does not compile:
extension Foo on String {
static String foo() => 'foo!';
}
void main() {
print(String.foo());
}
Error: Method not found: 'String.foo'.
print(String.foo());
^^^
What am I doing wrong?
The docs mean that the extension classes themselves can have static fields and helper methods. These won't be extensions on the extended class. That is, in your example, Foo.foo() is legal but String.foo() is not.
You currently cannot create extension methods that are static. See https://github.com/dart-lang/language/issues/723.
Note that you also might see Dart extension methods referred to as "static extension methods", but "static" there means that the extensions are applied statically (i.e., based on the object's type known at compilation-time, not its runtime type).
As James mentioned, you can't use the static method directly on the extended class as of today, the current solution to your problem would be:
extension Foo on String {
String foo() => 'foo!';
}
void main() {
print('Hi'.foo());
}
A common question, specifically since Dart 2, is if it is possible to require some or all generic type arguments on some or all types - for example List<int> instead of List or MyType<Foo> instead of MyType.
It's not always clear what the intention is though - i.e. is this a matter of style (you/your team likes to see the types), to prevent bugs (omitting type arguments seems to cause more bugs for you/your team), or as a matter of contract (your library expects a type argument).
For example, on dart-misc, a user writes:
Basically, if I have this:
abstract class Mixin<T> {}
I don't have to specify the type:
// Works class Cls extends Object with Mixin<int> {} // ...also works
class Cls extends Object with Mixin {}
Is there some way to make the second one not allowed?
Strictly speaking, yes, and no.
If you want to enforce that type arguments are always used in your own projects (instead of relying on type inference or defaults), you can use optional linter rules such as always_specify_types. Do note this rule violates the official Dart style guide's recommendation of AVOID redundant type arguments on generic invocations in many cases.
If you want to enforce that generic type arguments are always used when the default would be confusing - such as List implicitly meaning List<dynamic>, no such lint exists yet - though we plan on adding this as a mode of the analyzer: https://github.com/dart-lang/sdk/issues/33119.
Both of the above recommendations will help yourself, but if you are creating a library for others to use, you might be asking if you can require a type argument to use your class. For example, from above:
abstract class Mixin<T> {}
abstract class Class extends Object with Mixin {}
The first thing you could do is add a default bounds to T:
// If T is omitted/not inferred, it defaults to num, not dynamic.
abstract class Mixin<T extends num> {}
If you want to allow anything but want to make it difficult to use your class/mixin when T is dynamic you could choose a different default bound, for example Object, or even better I recommend void:
In practice, I use void to mean “anything and I don’t care about the elements”
abstract class Mixin<T extends void> {
T value;
}
class Class extends Mixin {}
void main() {
var c = Class();
// Compile-time error: 'oops' isn't defined for the class 'void'.
c.value.oops();
}
(You could also use Object for this purpose)
If this is a class under your control, you could add an assertion that prevents the class from being used in a way you don't support or expect. For example:
class AlwaysSpecifyType<T> {
AlwaysSpecifyType() {
assert(T != dynamic);
}
}
Finally, you could write a custom lint or tool to disallow certain generic type arguments from being omitted, but that is likely the most amount of work, and if any of the previous approaches work for you, I'd strongly recommend those!
I have a simple question but the google and stackoverflow results didn't satisfy me at all.
How can I define a Constants class like:
public class Constants {
public static final int SYSTEM_USER_ID = 1;
}
that can be called everywhere with Constants.SYSTEM_USER_ID
I tried it in grails-app/utils and src/java but for example I couldn't access inside a Service class.
You might consider putting these constants into Config.groovy rather than a class. One advantage of this approach is that you can specify per-environment values for these constants. You can read the values of these using either the implicit grailsApplication variable or the ConfigurationHolder class.
You need to put your Constants class into a package. Grails can't find the class if its not in a package itself.