1

So this is the code, which won't work due to "Case expressions must be constant"

void main() {
  final id = 'someIdA';

  switch (id) {
    case ConstantsClass.a.id:
      // do something
      break;
    case ConstantsClass.b.id:
      // do something
      break;
  }
}

// exposing all the constants but grouping the constants in class by class fashion
class ConstantsClass {
  static _A get a => _A();
  static _B get b => _B();
}

// wrapping all the constants related to A
class _A {
  final id = 'someIdA';
}

// wrapping all the constants related to B
class _B {
  final id = 'someIdB';
}

And I have read posts about this "Case expressions must be constant" issue: 1 2

But I don't seem to find an answer from those posts.

And I also try to find another way to do use a class that contains only constant fields: What's the best practice to keep all the constants in Flutter? [closed] which also gives me not much hope...

And I think there's no way for me to use class with constant fields like ConstantsClass in the code here, the best I can get is to put all the constant values in one class, which I think will be very messy...

so is there a better way?

edit1:

I have a lot of String literal values that I want to manage using class, like in the case that's discussed in Effective Dart

So I can't use enum, unless I need to convert every string literal to enum, which I'm not sure if it's possible...

Thanks!

Rémi Rousselet
  • 256,336
  • 79
  • 519
  • 432
Benjamin
  • 95
  • 1
  • 10
  • Is there a particular reason why you aren’t using enums? – returnVoid Sep 16 '22 at 18:17
  • hi I have appended that the reason why I'm using classes containing String literals, is because the class is been there already and there is a lot of it.... unless you are telling me that I have to convert all the classes to enum... – Benjamin Sep 16 '22 at 18:20
  • 1
    It will probably be worth the refactor. Personally I’d set the project up using an enum if the String literals are functional and don’t change. Bonus: all your strings are in one place. – returnVoid Sep 16 '22 at 18:29
  • 1
    I see, I have been getting similar advice to refactor the code, like simply just put all the string literals top level. – Benjamin Sep 16 '22 at 18:57
  • 1
    Oh, the classes are already there... That explains it. But yes, turning them all into an enum makes a lot of sense. Or just a List or Map of String, or as in my answer, a file of constants on top level. – Karolina Hagegård Sep 16 '22 at 20:50

2 Answers2

3

First, classes _A and _B don't have const members, so fix that. const class members must be static.

class _A {
  static const id = 'someIdA';
}

class _B {
  static const id = 'someIdB';
}

But now they are static, so you won't be able to access them via the ConstantsClass.a and ConstantsClass.b getters. However, I argue that those getters are rather pointless. That is, if you rename your classes:

class ConstantsClassA {
  static const id = 'someIdA';
}

class ConstantsClassB {
  static const id = 'someIdB';
}

and get rid of the ConstantsClass entirely, it doesn't make any difference to callers whether they use ConstantsClass.a.id or ConstantsClassA.id.

If you really want your classes to be grouped under some common namespace, you instead could name those classes A and B, put them in a separate .dart file, and always expect consumers to import that file with a prefix. For example:

import 'my_constants.dart' as myConstants;

void main() {
  final id = 'someIdA';

  switch (id) {
    case myConstants.A.id:
      // do something
      break;
    case myConstants.B.id:
      // do something
      break;
  }
}
jamesdlin
  • 81,374
  • 13
  • 159
  • 204
1

Ok, this is how I keep track of String literals, so that I don't have to worry about mis-spelling them, and it's also really quick and easy to access them without having to type the whole name:

//Keep these in a file called constants.dart
//and let all begin with a k:
const String kIdA = 'someIdA';
const String kIdB = 'someIdB';


import 'constants.dart';

void main() {
  final id = 'someIdA';

  switch (id) {
    case kIdA:  //Here, when you use your constants, you just type kia, 
    // and the IDE will fill in the constant name.
    
    // do something
      break;
    case kIdB:
    // do something
      break;
  }
}

If you still insist on a version using a class, I think this should work better:

void main() {
  final id = 'someIdA';

  switch (id) {
    case ConstantsClass.idA:
    // do something
      break;
    case ConstantsClass.idB:
    // do something
      break;
  }
}

class ConstantsClass {
  static const idA = 'someIdA';
  static const idB = 'someIdB';
  static const idC = 'someIdC';
  static const idD = 'someIdD';
}
Karolina Hagegård
  • 1,180
  • 5
  • 26
  • then I will have the error saying "only static field can be declared const" and I also try to add the static to it, but then it won't work in this `ConstantsClass.a.id` way since the field has become a static member. – Benjamin Sep 16 '22 at 18:06
  • 1
    Right. Well, see my updated answer and you have at least two suggestions that work without errors. – Karolina Hagegård Sep 16 '22 at 20:44
  • For the record, the Dart style guide recommends not using `k` before constants: https://dart.dev/guides/language/effective-dart/style#prefer-using-lowercamelcase-for-constant-names – lrn Sep 16 '22 at 21:23
  • 1
    @KarolinaHagegård thank you so much for your thoughtful and helpful answer, and yes both methods are feasible, I will go with one based on how much work is needed to change the existing codebase. – Benjamin Sep 16 '22 at 23:38
  • @lrn, I followed your link, but I don't see anything about using `k` to start constant names!... Can you quote the sentence, or the first sentence of the paragraph, you are referring to? In any case, starting all constant names with a `k` is unbeatably practical. I learned it in LondonAppBrewery's Flutter Bootcamp course. – Karolina Hagegård Sep 18 '22 at 20:09
  • The first line is "PREFER using lowerCamelCase for constant names." That measn `idA`, not `kIdA`, no artificial prefixes. The `k` is not part of the name here. – lrn Sep 19 '22 at 08:30
  • @lrn `kIdA` IS lowerCamelCase (for k + id + a), and it does not say anything about prefixes. Or short forms! "k" is short for "konstant" and "id" is short for "identification"! Both are equally right or wrong. My way works awesomely and aligns fine with recommendations, but you don't have to use it if you don't want to. – Karolina Hagegård Sep 21 '22 at 18:02
  • @Benjamin, don't tell me you un-accepted my answer because of lrn's comments...? If you did it because you liked the other answer better, I accept, it's a good one, but lrn's comments about the `k` prefix not following recommendations are just nonsense. (See above.) The LondonAppBrewery recommends the `k` prefix system, and their courses are the highest ranked Flutter courses on the web, so. – Karolina Hagegård Sep 21 '22 at 18:09
  • Sorry for not pointing directly to the "don't use prefix letters" rule: https://dart.dev/guides/language/effective-dart/style#dont-use-prefix-letters I guess `kIdA` is technically camel case, but Dart also recommends avoiding abbreviations (unless well established, `Id` is probably fine). All together, `kIdA` is not recommended, for a number of reasons. (Neither are constant-only classes, for that matter: https://dart.dev/guides/language/effective-dart/design#avoid-defining-a-class-that-contains-only-static-members). Flutter style does not always follow the recommended Dart style. – lrn Sep 22 '22 at 08:25
  • For context, a discussion about the prefix `k` on the Flutter issue tracker: https://github.com/flutter/flutter/issues/20858. Flutter has used `k` for some constants, Dart itself has never used `k`. It was `SCREAMING_CAPS` before the recommendation was changed to `camelCase`, both with no prefix character. – lrn Sep 22 '22 at 09:06
  • @KarolinaHagegård hey sorry for the late response, so, yeah, like your comment to another answer, that guy was making some rather unique perspective to the question. And honestly, your answer is not bad, I wish I could accept both, but this is how things work... I'm sorry and hope you can understand... – Benjamin Oct 03 '22 at 19:16
  • That, I understand totally! – Karolina Hagegård Oct 03 '22 at 19:19