4 ms·
I’m not sure about this. Is there a good use case outside of automatic more decent assert messages? That’s nice, but… (1) that’s far from a big problem in wri
by jmull 5y ago
I’m not sure about this.
Is there a good use case outside of automatic more decent assert messages? That’s nice, but…
(1) that’s far from a big problem in writing/maintaining unit tests. Isn’t the first thing you do with a failing unit test is examine the code on the call stack anyway? So this maybe saves you a click, assuming some pretty common tooling?
(2) I think you actually want to capture call stack source lines?
Not to mention, quite often the assert expression isn’t that interesting. e.g.,
var result = ComputeAnswer(“what is the meaning of life?”);
Assert.AreEqual(42, result);
The auto generated failure message would be something like: “result is expected to be 42 but was 41”
Whereas what you want is like, “ComputeAnswer(“what is the meaning of life?”) is expected to be 42 but was 41”
The style of separating the call to the code under test from the assert is pretty common, often recommended, and clean.
- moron4hire 5y agoMaybe if you gave your variables more meaningful names, like "meaningOfLife" instead of just "result", it would be more useful.
- jmull 5y agoIn that code snippet, “answer” would really be the right name for the variable (because the method is called ComputeAnswer). Redundantly restating immediately apparent context isn’t a good style.
- moron4hire 5y agoI cannot disagree with you any harder. Redundantly naming variables is good style, as it gives you more room to rename functions slightly, split functions, introduce new variables and inject new operations in the middle. And frequently, the function name has nothing to do with the semantics of the returned value. "result := sort(someOtherResult)" doesn't tell me anything. "sortedItems := sort(items)" tells me a lot. result1 := getUserInput() result2 := validate(result1) result3 := parse(result2) result4 := getRouting(result3) or addressInsecureStr := getUserInput() addressStr := validate(ipAddressInsecureStr) address := parse(ipAddressStr) pathAddresses := getRouting(ipAddress) I know which I would choose
- jmull 5y agoYou switched the context from a unit test to something different. Here, there I'd use something like this (changing some method names, too, since we're fixing names): userInput := getUserInput() validatedInput := validateUserInput() ipAddress := parseIpAddress(validatedInput) pathAddresses := getIpPathRouteTo(ipAddress) I'm making some assumptions about what these methods do and return. E.g., if validate/validateUserInput does something more specific than general user input validation then it should have a more specific name and the variable its result is assigned to would too.
- quietbritishjim 5y agoIn a function getMeaningOfLife(), a variable called result is perfectly meaningful. In fact I'd find it a better name than meaningOfLife, especially if you consistently result for all your functions. But yes you could rename the variable if you know it's going to be used in an assert like that.
- naasking 5y agoYes, it's also used in component models, like to auto-fill the property that changed to implement INotifyPropertyChanged [1]. I believe it's used in the MVVM toolkit, which has been getting positive press lately. It's apparently for building generic controller layers for a UI. [1] https://docs.microsoft.com/en-us/windows/communitytoolkit/mvvm/observableobject#simple-property https://docs.microsoft.com/en-us/windows/communitytoolkit/mv...
- forrestthewoods 5y ago> Is there a good use case outside of automatic more decent assert messages? Logging sounds like exactly when you want this and why it's useful? > is examine the code on the call stack anyway If it's running locally, sure! If you're inspecting logs from a CI system then not so much. Honestly I wish printing a callstack which also dump all stack variables. Including recent expression sounds pretty nice. Lord knows how many times I've gone back to add gratuitous logs because some Python script threw an exception and the callstack alone wasn't enough.
- jmull 5y ago> Logging sounds like exactly when you want this and why it's useful? Yes, that is handy… Log($”someValue = {someValue}”) can be Log(labelit(someValue)). That is a small nicety. > If it's running locally, sure! If you're inspecting logs from a CI system then not so much. Inspecting logs is a start, but if you don’t bring it back to the code you aren’t solving the problem. So you want a call stack. I agree an enhanced call stack would be even better, and expressions could be a helpful part of that. But CallerArgumentExpression doesn’t seem like a very good way to achieve that. For .net, I guess what you need is the symbol map (.pdb) and source code corresponding to the binary, and a tool to put it together — so that’s all achievable now, without CallerArgumentExpression.
- jve 5y ago> That is a small nicety. As I read it, it's more than that - you get to see the expression passed as an argument. If they would bake in that expression within NullReferenceException, well that would be so good... because there are methods that contain dozens of lines and that particular exception can happen almost anywhere. Usually I'm considering that when writing code and thinking: well this method can't throw NullReferenceException, just to be greeted with that particular exception at runtime, ugh.
- jmull 5y ago> If they would bake in that expression within NullReferenceException, well that would be so good... CallerArgumentExpression doesn't do that, though. I think you could maybe use it to do something explicit, like... someexpr.CheckNotNull().DoSomethingWithSomeExpr() where CheckNotNull() somehow uses CallerArgumentExpression to capture "someexpr" so that if someexpr was null, the exception could include the actual expression in the exception message. But that means decorating code with CheckNotNull() all over the place, which really limits this. What you really want here is a good call stack -- maybe with expressions, source lines, local variable values, etc.