Can I trust the order of parameter execution in C# function calls?
-
As I was rewriting my diagnostics, I decided test execution time was something I wanted to keep track of. But I'm a little lazy so I was wondering if this is safe:
DataTable d = new DataTable(); d.Columns.Add("Time1", typeof(DateTime)); d.Columns.Add("Function", typeof(String)); d.Columns.Add("Output", typeof(Boolean)); d.Columns.Add("Time2", typeof(DateTime)); d.Columns.Add("Time", typeof(TimeSpan), "[Time2] - [Time1]"); function TestFunctionX (DataTable d) { d.Rows.Add(Now(), "FunctionX()", (FunctionX("a")=="b"), Now(), null); }
Edit: In case it's not obvious, I'm expecting the second Now() to execute after FunctionX(), thus providing an execution time when combined with the first Now().
-
Pretty certain it's left-to-right ... let me check 'cos I've got the language reference handy ... yeah, "...the expressions or variable references of an argument list are evaluated in order, from left to right...".
And since it's the order of the argument list that is used, I guess
foo.bar(a:Now(), b:Now())
would be different fromfoo.bar(b:Now(), a:Now())
.
-
I guess the manual says you can, but I'd never actually depend on that behavior...
It's just such an obvious way for the compiler to optimize -- to run arguments in parallel -- that I would never trust a compiler to not want to. I mean, obviously, MS has programmed it not to. But will they always make that choice?
And if/when it changes, what kind of WTF will it look like to fix it?
I'd just pass in references to the arguments, (or for that matter, pass in a list containing all the references to all the arguments in order).
-
@Captain said in Can I trust the order of parameter execution in C# function calls?:
I guess the manual says you can, but I'd never actually depend on that behavior...
It's just such an obvious way for the compiler to optimize -- to run arguments in parallel -- that I would never trust a compiler to not want to. I mean, obviously, MS has programmed it not to. But will they always make that choice?
That's not an obvious optimization at all. Secretly evaluating arguments in parallel has two serious problems: 1) it can severely disrupt the semantics of the program (what if two different arguments are function calls that both take the same object as input, and one of them modifies it? Now we've introduced a race condition) and 2) the work required to launch multiple parallel tasks, wait on them to finish, gather the results, and put them in the right order adds a non-trivial amount of overhead, such that even if point 1 was not a concern, this would not actually be an optimization.
-
@Mason_Wheeler Blah blah blah
-
@Captain said in Can I trust the order of parameter execution in C# function calls?:
And if/when it changes, what kind of WTF will it look like to fix it?
They're internal diagnostics. I can just shuffle the calls around without breaking compatibility with anything outside.
@Mason_Wheeler said in Can I trust the order of parameter execution in C# function calls?:
That's not an obvious optimization at all.
Admittedly, I thought somebody could try that (and screw up tons of assumptions) but I didn't see any point in doing so.
Edit: Question on my mind now is why 300+ tests run in a fraction of a second but it takes 30+ just to show the window listing them.
-
@Zenith Compilers already do out of order execution "all the time", especially in highly parallel environments.
That said, my playground is not your jobsite, so listen to MW if that sounds more reasonable.
-
@Captain Again, the language reference states that the order of side effects (volatile reads/writes, exceptions, and initialisers) is preserved, so the second call to
Now()
will happen after the first. There is also a per-thread "as if" constraint.On the other hand, there is no guarantee that compiler optimisations will not largely or fully evaluate
FunctionX("a")=="b"
at compile time (absent any side effects) so that at run time it's virtually instant. But that would be true however the program is written.
-
@Captain I haven't disregarded what you've said. I have only a high level understanding of how out of order execution is supposed to work and no idea how it improves performance with that limited understanding. I do know there are a dozen layers between C# in the IDE and the physical hardware that the compiler's output runs on.
-
@Watson said in Can I trust the order of parameter execution in C# function calls?:
there is no guarantee that compiler optimisations will not largely or fully evaluate FunctionX("a")=="b" at compile time
If the function can be effectively eliminated by the compiler, then the function is so trivial that its execution time would be negligible anyway, and "0" would be a reasonable estimate.
-
@Zenith said in Can I trust the order of parameter execution in C# function calls?:
Edit: Question on my mind now is why 300+ tests run in a fraction of a second but it takes 30+ just to show the window listing them.
And the answer is...databinding with any sort of autosizing enabled, even row headers (300 rows = 3 minutes).
-
@Captain said in Can I trust the order of parameter execution in C# function calls?:
But will they always make that choice?
Categorically yes; the language semantics of C# (and Java too) are exactly defined in this regard. This isn't the free-for-all lackadaisical semantics of C++, after all; evaluation order is given in the language spec.
In reality, the compiler can shuffle things around as it sees fit, but only if the result is not observably different, and taking a timestamp is one of those operations that's always marked as being something that can't be omitted or combined or have code moved over. It'd be a pretty useless timestamp function if the compiler thought it was OK to just call it once at the start of the program and then reuse the result ever after! (These sorts of requirements are why modern optimizing compilers are so heavy on the formal semantics.)
-
@Captain said in Can I trust the order of parameter execution in C# function calls?:
I guess the manual says you can, but I'd never actually depend on that behavior...
I'd second that. If you have to ask in the first place, don't, it's just confusing.
There's no reason to not write the three more lines introducing the corresponding variables to make order of execution completely obvious.
Caveat: I don't write C#, so I wouldn't have been able to answer the question. Maybe if you're fluent in C# so much that the answer is "Duh, of course" the confusion is non-existent so it's worth the trade-off.
-
@Zenith said in Can I trust the order of parameter execution in C# function calls?:
And the answer is...databinding. No idea why that takes almost 3 minutes.
Rendering (non-text) values as text is very expensive for all but the most trivial of cases. Drawing on the screen is extremely expensive (and GUI frameworks do a lot behind the scenes to avoid doing the parts they don't have to) but that's probably not what the databinding cost is.
-
@dkf said in Can I trust the order of parameter execution in C# function calls?:
In reality, the compiler can shuffle things around as it sees fit, but only if the result is not observably different, and taking a timestamp is one of those operations that's always marked as being something that can't be omitted or combined or have code moved over. It'd be a pretty useless timestamp function if the compiler thought it was OK to just call it once at the start of the program and then reuse the result ever after! (These sorts of requirements are why modern optimizing compilers are so heavy on the formal semantics.)
Which is kind of interesting because "execution time" is usually not regarded as observable behavior, but only a side channel. Otherwise no "as if" optimizations would be allowed, because the whole point of optimization is to make things go faster.
But of course that doesn't make sense in context, so reading a time-stamp needs to be marked as communicating with the outside world and create appropriate fences.
-
@dkf You caught me. The calculated API list is passed into the constructor and I expected the control to do its sizing before ShowDialog() but I'd forgotten to turn off the row header autosizing. Even putting SuspendLayout() and ResumeLayout() around the binding call didn't help. The list is just a pile of structures with three strings and a boolean.
-
@Zenith said in Can I trust the order of parameter execution in C# function calls?:
And the answer is...databinding with any sort of autosizing enabled, even row headers (300 rows = 3 minutes).
I haven't done C# with databinding in a few years, but IIRC to make that work you need to disable the sizing, bind everything and than enable sizing again. Otherwise it fully resizes on every bind (and every update to a bind) which is slower than fuck.
Edit: ah, late to the party I see.
-
@Dragoon Yeah, I forgot, because for expedience's sake I used the framework's DataGridView instead of mine that fixes a ton of ugliness like that.
-
@topspin said in Can I trust the order of parameter execution in C# function calls?:
Which is kind of interesting because "execution time" is usually not regarded as observable behavior, but only a side channel.
The elapsed execution time is not observable, but the timestamps themselves are observations of external state.
-
@Zenith said in Can I trust the order of parameter execution in C# function calls?:
The calculated API list is passed into the constructor and I expected the control to do its sizing before ShowDialog() but I'd forgotten to turn off the row header autosizing. Even putting SuspendLayout() and ResumeLayout() around the binding call didn't help. The list is just a pile of structures with three strings and a boolean.
It was recomputing all the text lengths on every change, even when the changes were being thrown at it extremely quickly? That's one of the “really really expensive” things, and I'm a bit amazed that they thought that was a good idea. Jeez, sometimes I think this industry moves backwards; this is a problem that has had good solutions for at least 30 years!
-
No.
I had to fix a bug because of this assumption.
And even if it wasn't going to break, I would rather code be more explicit.
-
@dkf said in Can I trust the order of parameter execution in C# function calls?:
a bit amazed that they thought that was a good idea
Yeah, that'll happen with incredible frequency if you ever read through the controls section of the 4.0 reference. It's a real train wreck. Buttons drawing themselves twice, magic numbers everywhere, window messages that don't actually work, etc.
-
@Zenith said in Can I trust the order of parameter execution in C# function calls?:
In case it's not obvious, I'm expecting the second Now() to execute after FunctionX(), thus providing an execution time when combined with the first Now().
As @topspin mentioned, it's not so obvious, and probably won't be to the guy who has to debug this while being tired/stressed out. So this will definitely work, but you're better off with clearer code.
-
Obligatory Eric Lippert blog post:
-
@pcooper So what I proposed is ...
-
doesn't preclude . You could write it in Brainfuck if that was all that mattered. You're using a high level language because humans need to read it as well as machines. The fact that you had to ask the question in the OP means it's not obvious. Write your code so that it is obvious.
-
@error said in Can I trust the order of parameter execution in C# function calls?:
Write your code so that it is obvious.
Use named arguments.
-
@Watson said in Can I trust the order of parameter execution in C# function calls?:
@error said in Can I trust the order of parameter execution in C# function calls?:
Write your code so that it is obvious.
Use named arguments.
I name this argument "KISS".
-
@Watson said in Can I trust the order of parameter execution in C# function calls?:
@error said in Can I trust the order of parameter execution in C# function calls?:
Write your code so that it is obvious.
Use named arguments.
And don't worry about using local variables and extra lines.
-
Using multiple lines — rather, copy/pasting multiple lines over and over — just makes me itchy. Whose to say that some
start_time = Now();
won't be missed on the nth test, causing a bad timing for the (n+1)th test?I'd be wanting to wrap the repetitive stuff up in a function; and after that likely storing the tests (and their names) in a list to iterate over. The problem with that of course is that the test itself would have to be thunked for it to be passed to the function, and the overhead of unwrapping the thunk would count toward the timing.
-
@Watson said in Can I trust the order of parameter execution in C# function calls?:
and the overhead of unwrapping the thunk would count toward the timing
Unlikely to be above the timer's resolution.
-
@topspin said in Can I trust the order of parameter execution in C# function calls?:
@Watson said in Can I trust the order of parameter execution in C# function calls?:
and the overhead of unwrapping the thunk would count toward the timing
Unlikely to be above the timer's resolution.
And if you care about those kinds of microbenchmarks, then you're better of using BenchmarkDotNet anyway.
-
@Watson said in Can I trust the order of parameter execution in C# function calls?:
I'd be wanting to wrap the repetitive stuff up in a function; and after that likely storing the tests (and their names) in a list to iterate over.
Yep, I agree.
At the end of the day, @Zenith is implementing an applicative functor to do exactly what applicative functors are for (apply a function to its arguments in order). But without being explicit about it, in a language where that isn't a common idiom, it's going to bite you in the ass.
So if you're going to need an applicative functor, use the list of references, which makes it clear that the elements are ordered.
-
@Captain said in Can I trust the order of parameter execution in C# function calls?:
applicative functor
Sucker. Should'a gotten the endo model.
-
@boomzilla My functors are endo verendo
-
@boomzilla said in Can I trust the order of parameter execution in C# function calls?:
@Captain said in Can I trust the order of parameter execution in C# function calls?:
applicative functor
Sucker. Should'a gotten the endo model.
Which kind does one use for playing cricket? Or would use, if one were foolish enough to do that sort of thing?
-
Maybe it's just a waste of time to track tests individually. I'm getting alot that have suspiciously repetitive benchmarks (0, 00:00:00.0010000, 00:00:00.0010001, etc). I could just track blocks of tests? Or just drop the idea altogether. I looked at benchmarkDotNet. I had thought of using attributes for some recordkeeping (basically figuring out caller info) but no idea how they could use it to do benchmarks.
-
@Zenith said in Can I trust the order of parameter execution in C# function calls?:
Maybe it's just a waste of time to track tests individually. I'm getting alot that have suspiciously repetitive benchmarks (0, 00:00:00.0010000, 00:00:00.0010001, etc). I could just track blocks of tests? Or just drop the idea altogether. I looked at benchmarkDotNet. I had thought of using attributes for some recordkeeping (basically figuring out caller info) but no idea how they could use it to do benchmarks.
Do you need to benchmark all tests?
I would measure only- functions that are potentially performance problems
- functions that are called repeatedly in massive numbers
- mission critical functions that must be super fast
-
@Watson said in Can I trust the order of parameter execution in C# function calls?:
Using multiple lines — rather, copy/pasting multiple lines over and over — just makes me itchy. Whose to say that some
start_time = Now();
won't be missed on the nth test, causing a bad timing for the (n+1)th test?I'd be wanting to wrap the repetitive stuff up in a function; and after that likely storing the tests (and their names) in a list to iterate over. The problem with that of course is that the test itself would have to be thunked for it to be passed to the function, and the overhead of unwrapping the thunk would count toward the timing.
void TimedTest(string function, Func<bool> test) { var startTime = DateTime.Now; var result = test.Invoke(); var endTime = DateTime.Now; d.Rows.Add(startTime, function, result, endTime, null); } void TestFunctionX(DataTable d) { TimedTest("FunctionX()", () => FunctionX("a") == "b"); }
-
@Watson said in Can I trust the order of parameter execution in C# function calls?:
and the overhead of unwrapping the thunk would count toward the timing
If you need to measure something to the nanosecond, you probably want to execute it many times in a loop
-
@sockpuppet7 said in Can I trust the order of parameter execution in C# function calls?:
@Watson said in Can I trust the order of parameter execution in C# function calls?:
and the overhead of unwrapping the thunk would count toward the timing
If you need to measure something to the nanosecond, you probably want to execute it many times in a loop
I didn't say it was a big problem...