Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Share Static properties between Classes #4069

Closed
iPypeNB opened this issue Sep 1, 2024 · 6 comments
Closed

Share Static properties between Classes #4069

iPypeNB opened this issue Sep 1, 2024 · 6 comments
Labels
feature Proposed language feature that solves one or more problems

Comments

@iPypeNB
Copy link

iPypeNB commented Sep 1, 2024

In order to organize global constants in a dart project, I am looking to implement the following style, short example:

sealed class ConstColor {
  static const String black = '0x000000';
}


abstract class Constants {
  static const colors = ConstColor;
}

void main() {
  print(Constants.colors.black);
}

This is not possible because when I assign ConstColor to the static variable colors in Constants, colors is actually taking the properties of the Type class. Now, my goal is to continue keeping the constants as static properties so as not to load this data at the time of executing the call to Constants but rather to do so from the application load. What options do you recommend, or what other way is recommended to manage constants in an organized way?

Note: I ask the question here because I have been searching in the documentation, forums, etc. and I have not found an answer.

Thanks.

@iPypeNB iPypeNB added the feature Proposed language feature that solves one or more problems label Sep 1, 2024
@mateusfccp
Copy link
Contributor

mateusfccp commented Sep 1, 2024

One possible alternative is to do this way:

final class ConstantColors {
  const ConstantColors._({
    this.black = '0x000000',
    this.red = '0xFF0000',
  });
  
  const factory ConstantColors() = ConstantColors._;

  final String black;
  final String red;
}

abstract class Constants {
  static const colors = ConstantColors();
}

void main() {
  print(Constants.colors.black);
}

It will be a lot more verbose, but it does what you want. Once we have macros, you may use it to generate the class for you so it scales better.

@lrhn
Copy link
Member

lrhn commented Sep 1, 2024

I think you are asking for nested namespaces.
Dart does not have that.

See #266, #267 and #2272 (just from a quick search for "namespace").

The only way to have an extra namespace inside a class, is to have an object, as @mateusfccp suggests.
That does prevent the names from being accessible as constants.

@iPypeNB
Copy link
Author

iPypeNB commented Sep 4, 2024

Thanks for the reply 😊,

I think I'll wait for the macros or namespaces to come out for now, since the solution @mateusfccp propose seems more verbose and doesn't meet the objective I'm trying to obtain from the Sealed classes.

@tenhobi
Copy link

tenhobi commented Oct 23, 2024

Note you don't have to create fields in the nested class and init them in constructor. You can convert static fields to getters, add a const constructor and you get basically the same API as you want.

Something like this should work IMO

class ConstantColors {
  const ConstantColors();

  String get black => '0x000000';
  String get red => '0xFF0000';
}

abstract class Constants {
  static const colors = ConstantColors();
}

void main() {
  print(Constants.colors.black);
}

@lrhn
Copy link
Member

lrhn commented Oct 24, 2024

Or use fields, but don't bother with a constructor other than for the const-ness:

class Colors {
  const Colors();
  final String black = '0x000000';
  final String red = '0xff0000';
}
abstract class Constants {
  static const colors = Colors();
}

Or just use a record:

abstract class Constants {
  static const colors = (
    black: '0x000000',
    red: '0xFF0000',
  );
}

In any case, it's not a pattern I'd recommend. Nesting a bunch of values inside another object is just making access longer, with no real benefit. (Unless you expect to have different implementations of the interface, then it's not a namespace, it's a strategy object.)

If anything, the way I'd suggest organizing constants is putting them into libraries of their own.

// colors.dart
const black = '0x000000';
const red = '0xFF0000';

and people can import it as, for example:

import 'colors.dart' as colors;

Then people can control the name used. It doesn't have the direct connection to the Constants class (which is again not a recommended pattern).

And you can import only the constants you need. Providing all constants in the world as a single object just makes that a dependency of every file in the project. It'll be harder to see which constants are not used any more.

@munificent
Copy link
Member

Another approach would be to use both library prefixes and a class if you really do want two levels of nesting:

// constants.dart:
class Colors {
  static const String black = '0x000000';
}

// Other classes for other constants...

Then:

// main.dart:
import 'constants.dart' as constants;

void main() {
  print(constants.Colors.black);
}

But, in general, I would suggest not nesting constants inside classes. Top level constants are good and we should use them more often. If this were my code, I'd just do:

// colors.dart:
static const String black = '0x000000';

// main.dart:
import 'colors.dart' as colors;

void main() {
  print(colors.black);
}

Nice and simple. :)

I'm going to go ahead and close this issue because I think we've answered the question and pointed towards multiple solutions and other related potential language features, but I'm happy to discuss this more if you want.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Proposed language feature that solves one or more problems
Projects
None yet
Development

No branches or pull requests

5 participants