434457 (10) [Avatar] Offline
#1
Notes on Chapter 8 below:

Cheers,
Will


p1.

That doesn’t in anyway undermine their usefulness, however.


should be:

That doesn’t in any way undermine their usefulness, however.


p2.

possibly add units to the coordinates on the diagram - eg polar r and theta, cartesian x and y

p10.

Listing 8.7 shows an example of a schemaless entity type with two regular properties, but which otherwise allows arbitrary key/value pairs for its data.


should this be schema-less?

p13.

* One technique I’ve found useful in my work Protocol Buffers is to create Add methods accepting collections – effectively like AddRange, but with the ability to be used in collection initializers. ?


should be (with)

* One technique I’ve found useful in my work with Protocol Buffers is to create Add methods accepting collections – effectively like AddRange, but with the ability to be used in collection initializers. ?


p13.

* For example, consider a Person class with a read-only Contacts property that we want to populate with all the contacts from another list who live in Reading. ?


possibly a line-break before this sentence to split the paragraph

p16.

Unfortunately, it still exposes the Add method to the rest of the code in the same class, but again you need to way up whether that’s worse than the alternatives.


should be weigh:

Unfortunately, it still exposes the Add method to the rest of the code in the same class, but again you need to weigh up whether that’s worse than the alternatives.


p16.

Likewise, if you use indexers in your collection initializers for tests and accidentally put the same key twice, chances are very high that your tests will fail – so again, the downside it minimized.


should be is, in:

Likewise, if you use indexers in your collection initializers for tests and accidentally put the same key in twice, chances are very high that your tests will fail – so again, the downside is minimized.


p18.

The “overall expression” here – the part where evaluation stops abruptly if a null value is encountered – is basically the sequence of property, field, indexer and method accesses involved.


I think the correct word may be accessors:

The “overall expression” here – the part where evaluation stops abruptly if a null value is encountered – is basically the sequence of property, field, indexer and method accessors involved.


p18.

The compiler treats that roughly as if we’d written:


should be present tense/state:

The compiler treats this roughly as if we’d written:


p19.

There are two common ways of doing this: comparing against a bool constant, or using the null coalescing ?? operator.

using a colon with a list - probably should be bullet points or reworded

p19.

The behavior of bool? in comparisons with non-nullable values caused concern for the language designers in the C# 2 timeframe.


possibly should be comparison:

The behavior of bool? in comparison with non-nullable values caused concern for the language designers in the C# 2 timeframe.


p20.

There’s really not a lot more to say about how the null-conditional operator works with indexers – it’s as simple as that.


Does this check work with events/event handlers? It would be very handy (pardon the pun) if it did. Ah - answered on the next page.

p23.

Beyond occasionally at having to deal with nullable value types where you were previously only using non-nullable values, there are very few unpleasant surprises with the null conditional operator.


remove the at, tense before the subject:

Beyond occasionally having to deal with nullable value types, and where previously you were only using non-nullable values, there are very few unpleasant surprises with the null conditional operator.


p23.

The upshot of that is that you can’t use the null-conditional operator as the left-hand side of an assignment.


should be this (present tense):

The upshot of this is that you can’t use the null-conditional operator as the left-hand side of an assignment.


p23.


person?.Name = "";
In those cases, you simply need to use the old-fashioned if statement.


could this also be done using a ternary operator? (this was more just to prove that it could be done than an actual practical example)

e.g.

using System;
using System.ComponentModel;
namespace Chapter07
{    
    class TestPerson    
    {        
        public string Name = "test";    
    }    
    [Description("Listing Test")]    
    class Test    
    {        
        static void Main()      
        {            
            TestPerson test = new TestPerson();
	    //TestPerson test = null;           
            var noop = (test?.Name == null)? null : (test.Name = "");       
        } 
    }
}



p26.

Unless I’m confused, this line:

catch (Exception e) when (LogAndReturn("Bottom filter", true)) 


Will log ‘Bottom Filter’ and then enter into the catch block and then log ‘Caught in Bottom’

However, the order of logging is shown as:

Middle filter
Bottom filter
Top finally
Middle finally
Caught in Bottom

My understanding of the order of processing is:

Main() -> Bottom() -> Middle() -> Top() -> throw Exception() ->
Exception [
Catch in Middle() -> Log “Middle Filter” -> Catch in Bottom() -> Log “Bottom Filter” -> Log “Caught in Bottom” -> exception bubble completes ]
Finally [ Finally in Top() -> Log “Top Finally” -> Finally in Middle() -> Log “Middle Finally” -> finally bubble ends ]

This would give the following logging:

Middle filter
Bottom filter
Caught in Bottom
Top finally
Middle finally

Why is 'Caught in Bottom' after the two finally calls? There isn’t a throw in any of the finally blocks that I can see that would change this order.

Ok, the diagram on the next page comes to the same conclusion as I do, so the log list order on p26 is incorrect.

p29.

It didn’t make any sense, because by the second block would never be reached.


should be (no by):

It didn’t make any sense, because the second block would never be reached.


p30.

In short, it’s a pattern that doesn’t compose well with itself.


Isn’t this what the circuit-breaker pattern is used for?

p33.

So does this really meet the high bar for a new language feature??


From what I understand, exceptions are expensive performance-wise. Does ‘when’ go any way towards improving this performance cost or has the hit already been taken once the stack starts to unwind?
jon.skeet (479) [Avatar] Offline
#2
Finally got round to implementing these (mostly) now the reorg is done.

For the retry questions: I don't know if "when" improves performance at all, but I wouldn't make that a reason for using it; the circuit-breaker pattern is somewhat related to this, but doesn't really address the way that retries don't compose well. (It may be a workaround for that in many cases, but it doesn't actually stop it from being an initial issue.)

I probably won't add the r/theta/x/y to the figure, but we'll see what my copy editor thinks.
jon.skeet (479) [Avatar] Offline
#3
For the logging with the diagram - no, both the text and the diagram are correct:

Middle filter
Bottom filter
Top finally
Middle finally
Caught in Bottom

I'm not sure if the diagram was wrong at some point, but that's definitely the correct order. It looks like you expect the *body* of the catch block to execute before any intervening finally blocks - it doesn't, and never has.
434457 (10) [Avatar] Offline
#4
Thanks for that. Yes, that makes sense, albeit a bit confusing. So the "when"s are just iterated over first before the catch bodies are executed. Could possibly rename e.g. "Middle filter" to "Middle when" or "Middle when filter" to help when matching sequence to syntax?
The diagrams were definitely different but may have not been the latest version.
Thanks again.
jon.skeet (479) [Avatar] Offline
#5
I'd definitely want to include "filter" in there - it *is* an exception filter, it's just that "when" is the syntax for it.
"Middle when filter" is possible - I'll have to think about that.

Hopefully with the diagram and text saying the same thing, it'll be clearer anyway.