From the Dart language tour:
To test whether two objects x and y represent the same thing, use the == operator. (In the rare case where you need to know whether two objects are the exact same object, use the identical() function instead.) Here’s how the == operator works:
- If x or y is null, return true if both are null, and false if only one is null.
- Return the result of the method invocation
x.==(y). (That’s right, operators such as == are methods that are invoked on their first operand. For details, see Operators.)
https://dart.dev/guides/language/language-tour#equality-and-relational-operators
So the reason why operator ==(Object other) does not take null is because it is built into the language itself that comparing against null should always be false unless we compare with null. So you get this part of the comparison for "free", so you don't need to think about null input when you are writing your own == operator.
About dynamic vs dynamic?. As far as I know, they both represent the same so dynamic? is just meaningless. You can also see the analyzer and runtime will call it dynamic even if we check the signature of a method declared to return dynamic?:
void main() {
print(test.runtimeType); // () => dynamic
}
dynamic? test() { }