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 ?
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With