3

My goal is to create a button when you click on a disabled button it will print a specific message. But if you don't use the enable feature it will not ask you for the specific message in the constructor parameter.

Let say we have this class

class Button {
  final String label;
  final bool enable;
  final String disableMessage;

  Button(
    this.label, {
      bool? enable,
       String? disableMessage,
  })  : assert(enable == null || disableMessage != null),
        enable = enable ?? true,
        disableMessage = disableMessage ?? '';
}

I tried with an assert and conditional value but when I call it

Button('name', enable: false);

it doesn't display any error because this is only an assert.

I'm looking a way to have this behavior

Button('name'); // Good
Button('name', enable: false); // Error displayed
Button('name', disabledMessage: 'Button disabled'); // Error displayed
Button('name', enable: false, disabledMessage: 'Button disabled'); // Good

Is it a proper way to have conditional required parameter when another is used ?

1 Answer 1

1

it doesn't display any error because this is only an assert.

asserts throw an AssertionError if you compile with assertions enabled (e.g. debug builds). This is appropriate for logical errors (i.e., the programmer is at fault for violating an API contract) such as yours.

However, if you'd prefer for an error to be thrown in all build types, then you could do so explicitly. For example:

void alwaysAssert(bool condition, String message) {
  if (!condition) {
    throw AssertionError(message);
  }
}

class Button {
  ...

  Button(
    this.label, {
      bool? enable,
       String? disabledMessage,
  })  : enable = enable ?? true,
        disabledMessage = disabledMessage ?? '' {
    // Note that the function parameters shadow the member variables, so
    // `enable` an `disabledMessage` here are the local function parameters.
    alwaysAssert(
      enable == null || disabledMessage != null, 'Your error message');
  }

Note that the above copies the logic from your existing assert and therefore will throw an error if you do Button('name', enable: true). I don't know if that's really what you want. It also fails to fail for the Button('name', disabledMessage: 'Button disabled') case. I think you actually want:

  Button(
    this.label, {
    this.enable = true,
    String? disabledMessage,
  }) : disabledMessage = disabledMessage ?? '' {
    alwaysAssert(!enable == (disabledMessage != null), 'Your error message');
  }

But alternatively consider making the API simpler for callers by deducing enable:

class Button {
  final String label;
  final String? _disabledMessage;

  Button(
    this.label, {
    String? disabledMessage,
  }) : _disabledMessage = disabledMessage;
  
  bool get enable => _disabledMessage == null;  
  String get disabledMessage => _disabledMessage ?? '';
}

or by making separate constructors:

class Button {
  final String label;
  final bool enable;
  final String disabledMessage;

  Button(this.label)
    : enable = true,
      disabledMessage = '';

  Button.disabled(this.label, this.disabledMessage) : enable = false;
}
Sign up to request clarification or add additional context in comments.

5 Comments

"However, if you'd prefer for an error to be thrown in all build types, then you could do so explicitly." Thank for your detailed answer @jamsdlin. I don't want an error during the build but when you write the code. I don't want to make any braking changes of the actual button. That is why I try to add a mandatory message only if you set an enable parameter.
@BenjaminSx "I don't want an error during the build but when you write the code." That statement is self-contradictory. If you mean you want an error to be generated at compilation time instead of at runtime, then that won't be possible without changing your API.
I want an error when you write your code. Assert is the wrong behavior, I but it it to show what I have try but not what I wanted, I might be made some confusion.
@BenjaminSx Dart currently has no language features to do that. Again, you either will need to rely on a runtime error or change your API.
It's what I was afraid of. thank you for your confirmation

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.