Abusing C#
This is a modal window.
Das Video konnte nicht geladen werden, da entweder ein Server- oder Netzwerkfehler auftrat oder das Format nicht unterstützt wird.
Formale Metadaten
Titel |
| |
Serientitel | ||
Anzahl der Teile | 150 | |
Autor | ||
Lizenz | CC-Namensnennung - keine kommerzielle Nutzung - Weitergabe unter gleichen Bedingungen 3.0 Unported: Sie dürfen das Werk bzw. den Inhalt zu jedem legalen und nicht-kommerziellen Zweck nutzen, verändern und in unveränderter oder veränderter Form vervielfältigen, verbreiten und öffentlich zugänglich machen, sofern Sie den Namen des Autors/Rechteinhabers in der von ihm festgelegten Weise nennen und das Werk bzw. diesen Inhalt auch in veränderter Form nur unter den Bedingungen dieser Lizenz weitergeben | |
Identifikatoren | 10.5446/51450 (DOI) | |
Herausgeber | ||
Erscheinungsjahr | ||
Sprache |
Inhaltliche Metadaten
Fachgebiet | ||
Genre | ||
Abstract |
|
NDC Oslo 201390 / 150
3
4
5
6
8
11
12
15
17
22
26
27
31
32
39
40
41
42
44
47
51
53
56
57
59
60
61
63
64
66
67
68
69
71
72
79
80
81
82
83
85
87
89
90
93
94
95
97
98
99
100
101
102
103
106
108
109
110
114
118
119
120
122
125
126
130
132
133
134
135
136
137
138
139
140
141
142
145
00:00
BildschirmfensterSoftwaretestHochdruckGeradeEin-AusgabeMailing-ListeInertialsystemWurm <Informatik>Vorzeichen <Mathematik>ProgrammKlasse <Mathematik>LoopZeichenketteMinkowski-MetrikVerknüpfungsgliedSynchronisierungHydrostatikOvalSpielkonsoleFormation <Mathematik>PrimzahlzwillingeGenerizitätLaufzeitfehlerPhysikalisches SystemVirtuelle MaschineElektronische PublikationStatistikGewicht <Ausgleichsrechnung>GammafunktionLatent-Class-AnalyseAnalytische FortsetzungEmulationGruppenoperationStreaming <Kommunikationstechnik>C sharpAggregatzustandUniversal product codeZahlenbereichGeradeMereologieAttributierte GrammatikGruppenoperationProgrammierspracheProgrammierungInformationEin-AusgabeVersionsverwaltungZustandsmaschineDatensatzBitMathematikPunktCompilerBeweistheorieMakrobefehlTouchscreenTaskSpiegelung <Mathematik>CodeMaßerweiterungWellenlehreMAPHochdruckGüte der AnpassungDatenfeldDifferenteWinkelPoisson-KlammerMapping <Computergraphik>ResultanteProdukt <Mathematik>SoftwareentwicklerDeklarative ProgrammierspracheCoxeter-GruppeRechter WinkelMehrrechnersystemGerichteter GraphDemoszene <Programmierung>Gewicht <Ausgleichsrechnung>RückkopplungGraphfärbungUmfangFramework <Informatik>PhysikalismusNeunzehnÄhnlichkeitsgeometrieXMLUMLComputeranimation
08:56
Pi <Zahl>AggregatzustandSynchronisierungOvalHydrostatikVirtuelle MaschineSoftwaretestQuantisierung <Physik>GeradeInertialsystemAnalytische FortsetzungGruppenoperationPhysikalisches SystemSichtenkonzeptKontrollstrukturVirtuelle AdresseVerknüpfungsgliedZeichenketteElektronische PublikationSingularität <Mathematik>TaskQuellcodeStreaming <Kommunikationstechnik>Minkowski-MetrikPortscannerSchnelltastePrimzahlzwillingeInstantiierungKlasse <Mathematik>Spiegelung <Mathematik>Gewicht <Ausgleichsrechnung>BildschirmfensterRuhmasseAbfrageDickeSymmetrische MatrixGammafunktionDivisionInverseKreisbewegungNichtlinearer OperatorDemo <Programm>PaarvergleichReverse EngineeringENUMLokales MinimumSLAM-VerfahrenGenerator <Informatik>GasströmungDämon <Informatik>Zeiger <Informatik>Nichtlinearer OperatorAggregatzustandDickeMultiplikationsoperatorZeichenketteDifferenteWort <Informatik>MultiplikationAbfrageZustandsmaschineFolge <Mathematik>BefehlscodeOverloading <Informatik>Lambda-KalkülObjekt <Kategorie>Formale SpracheCASE <Informatik>GrenzschichtablösungMaßerweiterungSpeicherverwaltungSerielle SchnittstelleDatenfeldAbzählenBinärcodeNormalvektorBitInstantiierungDemo <Programm>Interface <Schaltung>Universal product codeQuellcodep-BlockFehlermeldungVerschlingungGüte der AnpassungQuick-SortPufferüberlaufCodeCompilerGeradeArithmetischer AusdruckFächer <Mathematik>InformationsüberlastungSystem FRechter WinkelVirtuelle MaschineZeitrichtungLoopWhiteboardPunktWeb logTablet PCVersionsverwaltungVierzigGruppenoperationComputerspielComputeranimation
17:48
QuellcodeSpielkonsolePhysikalisches SystemE-MailDämon <Informatik>GenerizitätInertialsystemBildschirmfensterSoftwaretestMenütechnikHydrostatikOvalDivisionInverseKreisbewegungSymmetrische MatrixNichtlinearer OperatorPaarvergleichDemo <Programm>Innerer PunktMinimalgradFunktion <Mathematik>GasströmungGenerator <Informatik>KommutativgesetzZeichenketteGanze ZahlWurm <Informatik>SCI <Informatik>Textur-MappingBildverstehenLokales MinimumSpiegelung <Mathematik>Gewicht <Ausgleichsrechnung>Minkowski-MetrikKlasse <Mathematik>Folge <Mathematik>ENUMReverse EngineeringAusnahmebehandlungFolge <Mathematik>Nichtlinearer OperatorCompilerNegative ZahlReverse EngineeringBitWellenlehreStapeldateiCodeOrdnung <Mathematik>C sharpSymmetrieTwitter <Softwareplattform>MathematikDivisionFunktionalDivergente ReiheFitnessfunktionGanze ZahlVerschiebungsoperatorVorzeichen <Mathematik>Minkowski-MetrikKategorie <Mathematik>VariableTeilbarkeitDigitalisierungResultanteSystemaufrufMultiplikationsoperatorAutomatische IndexierungATMPoisson-KlammerStreaming <Kommunikationstechnik>Formale SpracheElement <Gruppentheorie>InformationsüberlastungMultiplikationGruppenoperationKonfiguration <Informatik>Lesen <Datenverarbeitung>ENUMQuellcodeDreiecksfreier GraphDefaultCASE <Informatik>Betti-ZahlRechenwerkHochdruckURLÜberlagerung <Mathematik>EinsPartikelsystemComputeranimation
26:40
OvalHydrostatikFolge <Mathematik>GammafunktionFormation <Mathematik>SichtenkonzeptInertialsystemSoftwaretestKreisbewegungDemo <Programm>PaarvergleichDivisionInverseSpielkonsoleMenütechnikRechenwerkDämon <Informatik>HIP <Kommunikationsprotokoll>SimulationNichtlinearer OperatorQuellcodeObjekt <Kategorie>Dynamisches RAMEin-AusgabePhysikalisches SystemWechselsprungNormierter RaumGenerizitätE-MailRankingSpannweite <Stochastik>COMZahlenbereichDickeAbfrageSampler <Musikinstrument>ProgrammMaß <Mathematik>Software Development KitPrimzahlzwillingeMinkowski-MetrikGesetz <Physik>TrägheitsmomentCompilerStrom <Mathematik>DiagrammCASE <Informatik>Nichtlinearer OperatorDreisatzrechnungProgrammierungCompilerEinsFolge <Mathematik>DigitalisierungDifferenteVerschiebungsoperatorKontextbezogenes SystemLoopNegative ZahlReverse EngineeringInverseCodeDisjunktion <Logik>VerschlingungC sharpGüte der AnpassungSchnittmengeRechter WinkelKreisbewegungSpannweite <Stochastik>Quick-SortHochdruckInformationAdditionInstantiierungZahlenbereichAbzählenResultanteBitAutorisierungGanze ZahlIterationp-BlockOrdnung <Mathematik>SchnelltasteElement <Gruppentheorie>MomentenproblemVersionsverwaltungMultiplikationsoperatorKlasse <Mathematik>KontrollstrukturUmwandlungsenthalpiePunktKardinalzahlNormalvektorTeilmengeGruppenoperationErwartungswertBitrateComputeranimation
35:31
CompilerOvalBildschirmfensterSoftwaretestSpeicherabzugEinsGenerizitätMinkowski-MetrikFlächeninhaltHydrostatikHMS <Fertigung>Klasse <Mathematik>Ein-AusgabeStrömungswiderstandSpiegelung <Mathematik>Gewicht <Ausgleichsrechnung>Mailing-ListeProgrammTermVarianzMaß <Mathematik>Geschlecht <Mathematik>TrägheitsmomentLemma <Logik>DiagrammRechenwerkPi <Zahl>InertialsystemVersionsverwaltungEreignishorizontParametersystemCASE <Informatik>Message-PassingMultiplikationsoperatorQuick-SortFehlermeldungNebenbedingungHeuristikInstantiierungElektronische UnterschriftTypinferenzCompilerZeichenketteObjekt <Kategorie>Differenz <Mathematik>UmwandlungsenthalpieOrdnung <Mathematik>Gewicht <Ausgleichsrechnung>LaufzeitfehlerUmsetzung <Informatik>TypentheorieCodeValiditätKeller <Informatik>Schreib-Lese-KopfZahlenbereichBenutzerbeteiligungPufferüberlaufC sharpGruppenoperationGenerizitätPunktDifferenteZweiRechter WinkelVererbungshierarchieFormale SpracheKovarianzfunktionMetropolitan area networkFunktorGeradeSichtenkonzeptImplementierungNetzbetriebssystemNormalvektorBrennen <Datenverarbeitung>VarianzRuhmasseDatensatzEinfügungsdämpfungBestimmtheitsmaßSystemaufrufPartikelsystemTreiber <Programm>TopologieMatchingComputeranimation
44:23
Elektronische PublikationSoftwaretestInertialsystemVorzeichen <Mathematik>PrimzahlzwillingeProgrammSpiegelung <Mathematik>Gewicht <Ausgleichsrechnung>BildschirmfensterOrbit <Mathematik>Minkowski-MetrikGenerizitätPhysikalisches SystemGammafunktionHydrostatikFächer <Mathematik>FarbverwaltungssystemNormierter RaumDickeAbfrageSampler <Musikinstrument>OvalKlasse <Mathematik>Inverser LimesSpielkonsoleStrömungswiderstandNichtlinearer OperatorIndexberechnungZeichenketteZahlenbereichInnerer PunktObjekt <Kategorie>IterationZeichenketteKlasse <Mathematik>Nichtlinearer OperatorMultiplikationsoperatorSoftwareentwicklerVariableCodeVersionsverwaltungGeradeSpielkonsoleCASE <Informatik>ParametersystemTypentheorieBitLastVarianzVererbungshierarchieLambda-KalkülOpen SourceTypinferenzCompilerLoopZahlenbereichInformationProjektive EbeneElektronische PublikationInformationsüberlastungGewicht <Ausgleichsrechnung>DifferenteFolge <Mathematik>Schreiben <Datenverarbeitung>Auflösung <Mathematik>DateiformatUmsetzung <Informatik>FunktionalResultanteDatenstrukturKonfiguration <Informatik>Quick-SortGesetz <Physik>Abgeschlossene MengeRechter WinkelArithmetischer AusdruckSuperstringtheorieBildschirmmaskeGruppenoperationComputeranimation
53:15
Physikalisches SystemGasströmungMinkowski-MetrikSoftwaretestInertialsystemKlasse <Mathematik>OvalHydrostatikGammafunktionFormation <Mathematik>SichtenkonzeptVarianzNichtlinearer OperatorStatistikInnerer PunktZeichenketteSpielkonsoleSynchronisierungGewicht <Ausgleichsrechnung>TaskMailing-ListePrimzahlzwillingeArithmetisches MittelTupelEin-AusgabeAusnahmebehandlungDienst <Informatik>Innerer PunktTypentheorieFolge <Mathematik>TaskTupelBitSystemaufrufVollständigkeitPhysikalisches SystemKlasse <Mathematik>MaßerweiterungDemo <Programm>MereologieMusterspracheCodeArithmetisches MittelVerschlingungNormalvektorCompilerQuick-SortMultiplikationsoperatorUmsetzung <Informatik>NamensraumDatenfeldResultanteVariableDienst <Informatik>ZählenCASE <Informatik>RichtungAbzählenLaufzeitfehlerDynamisches SystemStandardabweichungDifferenteQuellcodeRechter WinkelProjektive EbeneFunktion <Mathematik>Schreiben <Datenverarbeitung>Gerichteter GraphHydrostatikGewicht <Ausgleichsrechnung>KreisflächeComputeranimation
01:00:29
XMLUML
Transkript: Englisch(automatisch erzeugt)
00:05
OK, I make it 20 past 10. Good morning, everyone. This is good. I had heard some rumors of Norwegians being reluctant to participate in things. I'm hoping this is untrue, so everyone wave your hands in the air.
00:22
Everyone go, woo! OK, good. Frankly, I live on the audience feedback, particularly for a session like this. Hands up, those of you who came here hoping to learn something useful about C Sharp. Go now! This is not intended to be a session
00:40
to help you with any productive C Sharp whatsoever. It is all evil stuff that you should in no way ever use in production code. They're neat little tips and tricks. Well, tricks, but not tips. When I first presented most of this code in Codemash, I had a few members of the
01:01
C Sharp development team present. Is Scott Guthrie watching this somewhere? No? OK. I was hoping that I could make him cry. Maybe he'll see the recording. So, yeah, trying to get any useful information about C Sharp out of this is like watching a Star Trek film and trying to get physics.
01:23
It's not going to happen, but I hope we'll have a lot of fun. It's just for entertainment. So I hope I can make you cry a little with some weird stuff. So let's start off with some not C Sharp, in fact. Some BASIC. How many of you started... How many of you had your first programming language was BASIC?
01:43
Good, I'm not the oldest one in the room then. So this was... We had BBC Micros at school, and typically everyone would start with something like this. I mean, in fact, the first version would just be 10 print hello, 20 go to 10. Everyone's done that.
02:01
So these are the good old days, and it's a bit of a shame that we can't do this in C Sharp. So we have something similar, labels, like this. We can do a labeled go to. We have the label up here, and then as soon as we say
02:20
go to loop, that will work. So if I run this code, and we want go to labels, it says hello, and we can say keep going, yes, yes, yes, and then say no. And that's all very well, but, oh, you've got to have this this label. Isn't it much cleaner
02:41
and obviously much more maintainable to have line numbers? Thanks to C Sharp 5, we can. So, here we have some code, and I'll run this code and then we'll have a look and see whether people can work out how it works. So this is go to async,
03:02
the first version. So we say keep going, keep going, and then we eventually stop. Let me just prove that this really is using the line number. So you can hopefully see it's probably quite small, but line 18 is this keep going. If we look down there, it says line 18.
03:20
So if I change this go to 18 to go to 17, it should now do hello, keep going, hello, keep going, hello, keep going, yeah? When I ran this at Codemash, I managed to run the wrong program at this point and was mortified that it didn't change anything. So there we go, hello, keep going, hello, keep going, and then we can say no. And just one final
03:40
proof point, if we go to 19, this should just say keep going once, but keep asking us for input until we do, until we press anything other than y. So, good. So are you satisfied that we've got go to with line numbers?
04:02
Satisfied that what I'm saying this program does, it actually does. Any ideas how it might work? It uses two of the new features of C Sharp 5. Macros?
04:20
No, we don't have macros in C Sharp. We're not Lisp yet. So let me reveal a little bit. Well, we can see that there's an await, and we're going to await a go to action. Let me reveal a little bit which is why I had to change screens and why I wasn't going to change the font size
04:42
again with everything up. If we just scroll over here a bit. So now everything's clear, right? No. So, um, we're clearly using async and await, but there are no tasks involved here.
05:03
Async and await basically builds a state machine. How many of you have used async a little bit? Even just to play around with. Have the basic idea, okay? How many of you have looked into some of the details of what goes on behind the scenes? Okay, good. Those of you who haven't, come to my talk
05:21
tomorrow, the last slot, basically, of the conference. I'm doing C Sharp 5, and exactly what level of detail I go into will depend on what people already know. But we may well cover the details there. So basically, an async method, the compiler builds a state machine for you,
05:40
and it's all based on go-to. It remembers what state you're in, and when you await, it says, okay, I'll remember where I am, and then later on you can come back to the same place. Which is very nearly what we're doing, except we're saying we don't want to come back to the same place, we want to come back to somewhere else.
06:03
Which is basically, if we have a state machine, and it has a field remembering its state, all we've got to do is poke that state with a different value, and things will be okay, right? So, here I await underscore, which is a
06:20
line action. Line action is just a delegate, but I'm actually awaiting the results of calling this delegate, and when I show you the declaration of line action, it will make a bit more sense, hopefully. So, line action is a delegate that has call a line
06:40
number attribute for on the parameter, which means if you don't specify a value for this parameter, it will fill it in, the compiler will fill it in with the line number. So, effectively, our code is await,
07:01
this is 17, 18, 19, 20, et cetera, et cetera. And then, what this is actually doing behind the scenes, so we have this go to executioner, remember the line action part and the go to action, I think go to action is just another delegate, and go to executioner
07:22
remembers a mapping from line number to the internal state number that the state machine is generating for you. And it does this by when you await something, this line, so it's going to, at some point,
07:40
it will call our entry method passing in this line action that we're going to call to remember the line numbers. And if I go to executioner, so it passes in the line method created as a
08:00
delegate for the record the line number part and go to for the rest. So, the line method, when you call it, it returns an awaitable. And that awaitable remembers, when you await it,
08:21
it remembers the state that you are in when you await it. So we have a create awaitable, I have this idea of a state machine there's already iAsyncStateMachine is part of the framework, but I have various extensions on top of that which basically use reflection to
08:42
fetch and poke the state. So we happen to know that the generated state machine always contains a field called angle brackets one underscore underscore state. So all we need to do is fetch the value of the state when we await because the compiler will have
09:03
when we're executing it the compiler will store that state so that when we come back to it, all we've got to do to come back to that line is poke it with the same state that it is when we await it. So that's what getState and setState do
09:22
and all our go to executioner does is create an awaitable which always says yes, I need to await, otherwise the state machine won't actually bother doing all of the rest of the stuff and then it's got this, a yielding awaiter has a cunning thing to say
09:40
right, what should we do when we've completed? Either keep going as we were or go to somewhere else. The details of all of this are fiddly, to say the least. I will attempt to make the code available at some point, but do you basically get the basic idea? So if we've got a state machine
10:01
what else could we do with it? Well in fact I think it was Kirill Asenkov blogged a version of this, but one thing you can do with state is save it. So I have another example saveState where the method just looks like this
10:23
so the first time we run it we'll see this looks like this is the first time through and we can just keep going until we hit n so yes we'll keep going and then we're bored, so i is 4 let's just finish there and then next time we run it, i is 4
10:45
again, and we can continue and we're bored again so these are genuinely separate processes we're just saving the state and yes, yes, yes and then we've completed
11:00
and we can add something else so we could put string sorry, let's get the current time the start time obviously you wouldn't use dateTime.nail
11:20
in production code because it's horrible in various different ways would you? you would use nodatime, right? okay so let's just put so this will be in a loop, kind of nasty but
11:40
okay, so we'll have deleted the state because we completed last time so if we start up okay, so it started at 10.31 keep going, keep going bored now 10.31.49 we're looking for saveState 10.31.49, and it keeps going and we didn't have to say anything about
12:01
well, we've got another variable to save even though this is a local variable the way the state machine is built it will end up as a separate object in fact it's a struct on the stack until it needs to be an object on the heap because the way that async is implemented is quite ridiculously efficient
12:20
it's horrible the hoops they go through to make it efficient but it's great that it works so all I'm doing is taking the instance of that state machine finding only those fields which I actually want to persist because there are some that I don't saving them just with the normal
12:41
serialization just a normal binary formatter and I'm going through a few little bits and pieces so that we can save null references as well and that's all it does right, I shall leave I have another demo of retrying stuff
13:01
so it's more of the same really, we have a state machine imagine you could try some stuff and if it failed, a bit like on error resume next except this is on error, just go back to where we were because we don't want to bother writing a loop and a catch block and whatever, just if something goes bang, just put us back to where we were before
13:22
but it's more of the same, so relatively boring let's look at some link now sort of old school back in C sharp 3 I love link, do you all like link? what do you like about it?
13:43
it's good I'm looking for a little bit more detail you're one of those people that ask questions on stack overflow saying my code doesn't work I'm sure you don't really composition composition, yes, that's good pardon expressiveness yeah
14:01
the problem with link is it's so wordy you have to write so much code we really want to make something a lot more concise so let's have a quick basic demo of I don't want to write all these words I would rather like operators
14:21
because I'm a Perl fan so instead of writing concatenation and where and select and things, I really want to use sort of and as my where clause and pipe as my select clause
14:41
because then I save whole characters it's really important so let's look at what we think this link to operators code should do we've got hello world how are you and then we're going to subtract world so the idea is I've taken every operator that you can overload
15:01
in C sharp and overloaded it on this I can't remember whether it's called evil innumerable or something like that, operator innumerable so every single operator does something and we'll have a look at what some of them do in a bit so we're going to take away world leaving hello hello how are you and then we're going to add in today
15:22
so that leaves hello how are you today and then we're going to filter it and is generally for kind of filtering ish operations so this is our where clause so we're only going to keep words of length five and then we're going to uppercase them
15:40
oh and then we're going to write out this query three times so if you've got a sequence I'm not sure but I think python even if it doesn't have multiplication for sequences I think it does for strings if you do hello times three it will return hello hello hello is that right any python people yeah okay so I'm only
16:01
giving this as an example of what not to do but you know some languages do something like this so I reckon this should show hello world today hello world today hello world today all in uppercase yeah and it does oh sorry without the world because we subtracted world
16:24
so that's the basic example and all of this is actually reasonably simple as soon as you've I'm not kidding on this case so if we look at the evil extension method all that does is create an operator
16:40
enumerable because you can't overload operators on interfaces sad the evil we could come up with if we could overload operators on interfaces wow we could have a lot of fun then but no we've got to create this operator enumerable which just remembers the source and it remembers it as
17:01
inumerable of object because hey we might as well it makes various other things interesting and then we've just got the operators so we have seen and which just returns where I'm not going to re-implement all of linked to objects that would be crazy that would be an
17:22
entirely different talk but we've got where we've got select the unusual thing here is normally operator operands aren't delegates I can't remember ever seeing something where you use a lambda expression as an operand
17:41
so that's in some ways all that's different here just as random examples of what we've got so here we have arithmetic minus plus star and slash any ideas what's going to happen when we use plus plus source and minus minus source what would it make sense to do
18:08
let's see so we start off with arithmetic minus plus star slash when you add a plus to it it adds a plus just adds a little plus sign
18:20
when you take away minus minus minus we take away the minus sign it's kind of simple any other operators that you can think of that might have fun things plus equals is just concatenation we've seen normal concatenation
18:42
so you only overload the plus operator so that's relatively straightforward division was that excellent that's what I was about to show so we can use division in multiple ways what would you expect to happen if we divide a sequence by something
19:01
pardon group by yes so that's one option so here we have a bunch of employees and we're going to divide by a delegate returning the department so let's run it and then I'll see if I can move the
19:21
okay so division by a function let's just concentrate on that bit first so we can see this is exactly doing group by so accounting has Dave sales has Bill and Betty finance has Holly and Edward and engineering has Diane and Tom so that's division by a function
19:41
for group by we could also divide by an integer which is just you know let's batch up this sequence into groups of in this case five so if we start off with to be or not to be and we just split it by spaces we get
20:01
ignore the fact that we've got extra commas because of the commas in the text and if we're going to make division by an integer divide things into batches then we'd like that to give you know whole batches which means your remainder operation can then do whatever left at the end so
20:20
division returns a sequence of sequences and then the remainder just shows whatever's left whatever doesn't fit into the final batch how about the bitwise yeah bitwise negation
20:41
the twiddle operator what does it look like a wave it's kind of a bit here and there and everywhere so I thought it would be quite fun to do a shuffle so when we run this twiddle items
21:02
who knows it might come out in any kind of order yes now most of these operators that I've used don't change the thing that they're called on which is a good thing however I would like to
21:22
show you the hideousness of the unary operators so this little segment owes itself to Eric Lippert who used to be on the C Sharp compiler team and is now working for Covarity and I think it was in the
21:41
annotated C Sharp spec he said the unary plus operator is the most useless thing that you could possibly have it's only there so that you can put plus ten as well as minus ten and you know for symmetry I'm not entirely sure whether this code proves him right or
22:00
proves him wrong however if we're going to have we've got the unary plus operator and we've got the unary minus operator now when I was first coming up with this code I asked various people on Twitter what they would want to do with the unary minus operator so that's the operator that is not x minus
22:20
y but just minus y okay I've closed this so that you can come up with some ideas of your own any suggestions? backwards? okay reversing? yes that's one option I've got shifting as the shift operators
22:40
because those feel kind of sensible put it this way I think shifting with the shift operators makes a lot more sense than writing to a stream or reading from a stream what kind of crazy language would do that? so not shifting but someone suggested
23:00
element wise negation if they're integers we can just negate them and someone else suggested something truly hideous which is it should pop it should return one element and remove it from the thing that it's operating on never ever ever ever
23:20
do this so just generally operators shouldn't change the thing that they operate their operands so we've got three different ideas there reversal, negation and popping now the unary minus operator doesn't take
23:40
any operands other than the thing it's working on so if we've got three different potential operations we need some way of you know switching between them so this is what the unary plus operator does imagine that we have we've got an enum of reverse negate pop reverse negate pop and we can just cycle between them and I think it starts off
24:01
by default it reverses and if you use the plus operand that returns a new one it's not crazy enough to mutate the existing one it returns a new one that has the next kind of behaviour for the unary minus operand so if we start with these adjusted the first few digits of pi
24:21
when we print them out we'll see three one four one five nine two a single minus will just reverse but if we use plus sequence and then use minus on the result who would have thought this would even be valid then it will negate each thing
24:42
unfortunately we can't do plus plus sequence in order to advance it by two because that would use the plus plus operator out of interest let's see does this work
25:04
the operand must be a variable property or indexer no I don't think it's liking that so we could potentially make the plus plus operator let's just change what the plus plus operator does to make it return plus plus sequence and then we might
25:21
be able to get triple plus to work which would be awesome so that's a reasonably simple oh it's still not liking it so we can do that and now
25:40
we can just do plus plus sequence and it will do the same thing so I think you can do these in as many batches of two as you want oh no it doesn't like using plus plus on something else so we'll have to make do with these two
26:02
but we can probably get rid of one bracket there there we go right so when we've done plus plus sequence it will now go into popping mode and each time we call minus popping it will return one element and remove it from the current
26:21
thing so if when we print out popping so we'll have popped I can't remember which end it pops from but we'll have either removed 314 and it will print 1592 or we've removed 295 and it will print 3141 and then if we reverse the
26:41
if we take the original sequence and go through one addition to get to negation one addition to get to popping and then one addition it should go back to reversal so when we then do the unary minus operator of that it should just print out the reverse so 295
27:03
1413 etc let's see unary operators 314 okay so pop takes it from the start and it all works of course we could change the minus minus operator to do minus minus which in the case of popping would be bizarre
27:24
in all kinds of ways actually in the case of reversal would do nothing because it would reverse it twice and in the case of negation it would also do nothing or go bang when you tried to print it depending on whether you were actually printing numbers or not
27:41
sorry? the last reverse didn't work let's check that I'm sure you're right but uh unary operators oh you're right what on earth is going on there? yeah but when we
28:02
take plus plus sequence the plus operator does take a copy or it should at least yeah let's take so something is badly wrong here
28:21
so this is now no longer using our crafty right yep no idea what's going on there might have a look later on um what does this do? there's no reason why that shouldn't
28:40
work that I'm aware of okay bizarre um so I think we've probably proved that Eric Lippert was right and this isn't a strictly speaking good idea right um any other oh yeah you can multiply two sequences together
29:01
and you know you get cross multiplication so this will do uh A1 A2 A3 B1 B2 B3 C1 C2 C3 I think yep um I've already mentioned the shift operators uh for rotation um so
29:21
you could make the shift operators or at least you could make right shift get rid of things in the same way that right shifting an integer you know loses information um but no I just I just rotate the whole thing um inverse oh yeah so not of a sequence this is quite fun so what does not of a sequence
29:41
mean? I've defined it to be sort of an inverse of the possible sequence so it is it's not something that on its own is useful but when you add another sequence to it it removes all of those things it's sort of like dark matter
30:00
it will obliterate anything else so um when we've got when we add the range 0 1 2 3 4 5 6 7 8 9 to the inverse of the first seven digits of pi it will only produce those digits which aren't in the first seven digits of pi if I remember rightly
30:23
there we go 0 6 7 8 ok I think that's probably enough linked to operators how am I doing for time? fine uh so that was that was the not operator not on a sequence
30:47
I've got two ones yes it's treated as a set wise inverse um basically because I didn't want to rewrite everything and I just wanted to use except the normal except link operator um are there any other operators you would like to see I can't think of
31:01
any I've missed off at the moment oh there's true and false um so you can do if sequence and other sequence um but sorry is there a oh is there an exclusive or operator I'm sure there is uh let's
31:20
see what it does um ba ba ba exclusive or um oh is is except so um it returns um elements that are only in one of the two sequences so you know exactly as you'd expect
31:41
think of it as bit wise and just I'm doing it with sequences so let's uh let's show that um so um two bar bears dot evil
32:01
uh x or two um um quacks bar dot evil so I reckon this should print um foo baz quacks after the stuff that came before yeah foo baz quacks
32:22
um I've shown pipe and and just looking at the top of the keyboard yeah that looks like it's all the operators available um always worth playing around okay so quiz time next uh next thing is version detection so this is where I tried to stump the C
32:41
Sharp team and it was quite fun um C Sharp has had how many versions it's had six versions 1.0 1.2 2.0 3.0 4.0
33:00
and 5.0 and the C Sharp team is very keen on um backward compatibility so ideally any program that previously compiled if you compile it with a new version of the C Sharp compiler it should do the same thing right so I took this as a challenge to break C Sharp
33:21
um and try to come up with a program that would compile on not necessarily all versions of C Sharp but um in order to compare any two versions it should compile on both the old and the new and give different results um so I've hidden them here so that we can
33:41
see if anyone can work out any differences my guess is that you won't get the first one how can we detect the difference between C Sharp 1.0 and 1.2 and I've no idea why it wasn't 1.1 any ideas okay I
34:01
have it on some authority that in C Sharp 1.0 when you use a for each loop okay let's rewind a little bit when you use a for each loop it calls get enumerator yes happy with that and whatever is returned by get enumerator so the I enumerator usually
34:21
the non generic I enumerator that was present in dot net 1.0 didn't implement I disposable I believe ish in C Sharp 1.0 that enumerator was never disposed whereas in C Sharp 1.2 conditional code was added saying if the enumerator
34:42
happens to implement disposable then dispose of it at the end of the for each loop just like it does for I enumerable of T where I enumerator of T implements I disposable really important so that finally blocks in in iterator blocks execute
35:02
so in order to detect the difference we create our own funky class which implements both I enumerable and I enumerator because we don't care we're just going to say it doesn't have any values and it's its own enumerator all it's going to do is remember whether
35:20
or not it was disposed we're going to for each over an instance of it and return whether or not it was disposed now I've been somewhat cautious about this saying you know I think this is the case I looked at the specification it's relatively hard to even find the C Sharp 1.0 specification and the diff isn't terribly helpful
35:43
but I believe the 1.0 spec does say that it should dispose and I have this idea in my head that it doesn't it's quite hard, it's hard enough to get hold of the spec it's really hard to actually get hold of the C Sharp 1.0 compiler because it won't install on any modern operating systems
36:00
I need to find someone with XP and see if I can install install it on that so what do you normally do if you believe something to be true and you want to check it and you can't prove it directly I can wait here all day pardon?
36:20
you can ask on Stack Overflow in general you can search the web right? and I did find a number of references stating that this is the case unfortunately they were all me so I'm not going to claim that this is definitive I really really want to see this in action sometime
36:42
I must have got the idea from somewhere, that's kind of all that's giving me hope at this point so that's 1.2 to 1.0, what about C Sharp 2 and C Sharp 1.2, so we can't use generics or anything like that because we know that that just wouldn't have compiled in C Sharp 1.2
37:01
so can anyone think of any differences in C Sharp 2 that you'd be able to detect pardon? events what about events? shout loud
37:22
events themselves existed before you're along the right lines it's around delegates, or at least the thing I'm thinking of is around delegates that man is right, give that man a prize if we have one
37:41
so the gentleman said it's covariance and contra-variance of delegates so when you create a delegate back in C Sharp 1, remember we've got to do the new event handler stuff, we can't just do button dot click plus equals do stuff it's got to be button dot click plus equals new event handler do stuff
38:02
and in C Sharp 1 the signatures had to match absolutely correctly so if you had a mouse move handler in order to create a mouse move handler you had to have a method that took mouse move event args in C Sharp 2 you can have
38:21
something that takes just event args on the grounds that anything calling it as a mouse move handler and passing in a mouse move event args or mouse event args, whatever it is that's going to be fine and valid so, we know that one conversion isn't valid in one case and is valid in another, how can we
38:40
use that to prove which version we've got? we can't use is we've got to have something that compiles first we can't cast, so we've got to have some code that does new
39:02
some kind of delegate type and pass in a method how can we differentiate? I'll show you it's the same trick that we're actually going to use in various different cases if we have a base class with just the general version so the event args version
39:22
and a subclass, sorry in fact why don't I make this something more familiar mouse event args mouse move event args oh, someone tell me what the add a reference to winforms there we go
39:55
and that one takes event args so here we have a general one and we're going to do new
40:02
where is that event no, I was fine before okay, ignore me right, so imagine the mouse move event args and event args but taken up a higher level if you've got a method that can take any object at all for the second parameter
40:20
it can definitely take an event args, right? so, if we try to use just normal event handler so the signature of event handler is object sender event args args, right? if we try to create this from derived, so we're creating an instance of derived and the compile time type
40:40
is also variant derived so we've got this, and we say create me an event handler using the foo method in C sharp one the compiler would first look at this foo method and say, no, I can't use that that second parameter is wrong tell you what, I'll look at the base class instead
41:03
and then it finds something, so it ends up using the right it ends up using this base implementation the C sharp two compiler says no, that's fine, I can use this more derived method these are two separate methods, this isn't overriding this is overloading
41:22
I can use this the second method because object args is compatible this signature is compatible with the signature of the delegate so all we need to do is see which one is called, and basically we assume it's false, and if the derived version is called, then we call it with true
41:41
okay how about C sharp three the way that generics behave can you give more details in respect to contra-variance and co-variance that was C sharp four
42:01
so the .NET runtime has had support for generic co-variance and contra-variance back since .NET two but C sharp as a language only allowed out and in in C sharp four but you're close it is around generics anything else happened
42:21
in generics in C sharp three pardon? type inference, yes give that man a teddy bear so in C sharp two type inference was pretty dumb Haskell and F sharp people will say it's still pretty dumb in C sharp three
42:41
but it was really pretty dumb in C sharp two so you had a bunch of parameters and a bunch of type parameters are we all clear on the difference between a type parameter and a normal parameter? yeah? so if you had a generic method with one type parameter T
43:02
and two actual parameters both of which were of type T then type inference would try to work out T from each of the arguments that you passed and then say are those all correct do they all match? exactly in C sharp three it takes a much more sort of heuristic
43:21
view of things, holistic rather and it says well I'll look at all the arguments you've given me and work out what kind of constraints I've got and then try to find something that matches all of those but they don't have to we're not trying to work out the whole of everything about T from each argument individually so that exact example that I gave
43:41
we've got a foo of T that takes T for both parameters and as our sort of backstop let me just undo this if I comment this out we're going to try to create, we're going to try to call foo with an object
44:01
and a string so in C sharp two it would say hey I know what T is it must be object for the first argument and then the second argument would say I know what T is it must be string and then the two of them would look at each other and say you're wrong I know best, oh compile time error
44:20
so if we were to try to compile this code now on a C sharp two compiler it would blow up now I've said we don't want it to blow up we want it to compile and then do something different so let's add an overload to keep these two arguing arguments
44:40
happy, didn't think of that before to stop them from arguing we'll say you can do T one, you can do T two they can be completely separate it's alright, you don't have to share so the first argument says right, T one must be object and this one says T two must be string and they look at each other and say that's fine
45:03
but in C sharp three it will still prefer this version because overload resolution first looks at the most derived class and says right, can I find anything in there that will match and it says yes T can be string sorry, T can be object
45:22
because string is an object so that's fine, so I'll use that overload so again, all we need to do is return true or false happy? okay, you've done pretty well so far, I have to say C sharp three to C sharp four I haven't got it in this file, I've got a slightly separate file
45:43
any ideas? hold that idea for later on but this is C sharp three to C sharp four
46:00
you're absolutely right, I'll come back to you for C sharp four to C sharp five anyone, what are the differences in C sharp three and C sharp four? what were the features of C sharp four? named parameters yes or named arguments and their partner in crime optional parameters yes
46:21
how long have optional parameters been around in .NET? since the beginning yes, so if we have a separate assembly so we compile this with this has to be compiled with the C sharp four or up compiler but it can still target .NET 2
46:41
so we're still going to be fine to use the C sharp three compiler to compile something that refers to this assembly and look, it's the overloading and base class trick again so all we're going to do is call detect defaulting without any arguments and that will be entirely valid to do
47:01
whether we're using C sharp three or C sharp four, it's just it'll use a different overload, so this is worth, I said you wouldn't get anything useful it's just possible that this could actually come up in reality if you've got say a visual basic assembly that you are referring to, it can happen
47:21
and it's got this sort of structure then if you're compiling with C sharp three and C sharp four you could get radically different results and again we just return false if we haven't got the defaulting and true if we have okay so that's C sharp three C sharp four, finally C sharp four to C sharp five, you had a great idea sir
47:49
they've changed the scoping of variables in which particular loop? in for each, yes so the way that the iteration variable of a for each loop is captured by
48:01
an anonymous function whether that's a lambda expression or an anonymous method has changed in C sharp five entirely silently and this is worth knowing if you're an open source developer if you've got some developers using visual studio 2010 and some using
48:21
2012 then someone could check in code that works fine against their compiler and will fail against the will fail silently with the 2010 compiler because it will still be valid code just something that does the wrong thing so here we have in
48:40
C sharp four there was one variable so our bool value would be as if it were declared outside the loop and then it would then take on each value within the sequence as we went along and when you captured that variable it captured the single variable even
49:01
if you captured it several times so when you look at the end if you use that variable that's captured after the loop has finished you will always see the final value in C sharp five it's different and much saner we get a separate value variable for each iteration
49:21
of the loop so we're capturing that and then we're just going to see at the end what happens if we find out what the variable the variable that we captured on the first iteration of the loop what's its value now and in C sharp four we'd only have captured one variable so it would have a value of false in C sharp five we'd have
49:41
captured only the variable associated with true so it would still have a value of true right all happy with version detection? I should point out these are corner cases and in the case of at least the variants of delegates the compiler would normally
50:01
warn you saying hey this behavior has changed between C sharp two and C sharp one and I think for type argument type inference it might do as well I'm not sure I think I've disabled all the warnings to avoid giving hints um okay finally and this is actually in some ways my favorite because it's
50:22
it's the most elegant oh no we've got loads of stuff to do and not much time okay let's give you a crazy thing to start with right what's that code going to do we haven't got much time come on what's this code going to do sorry
50:41
it will print out zero one two three four five six seven eight nine ten sorry not ten uh not to nine yes I don't want it to go up to ten I only want the first five numbers so we'll just do limit equals five is that okay well
51:03
yes it is okay but this outputs a bit boring it it may be a little bit harder to read from the back so let's put the current value of x is is that going to be clearer
51:22
let's see yeah that's clearer now it says zero one two three four so you can see that um that this this is a perfectly simple project what's going on implicit operators well but
51:42
where are these operators coming from VAR is a class ah he's it's a class that's sneakily hidden within assembly info dot cs and yes there is an implicit operator to VAR from both string and number
52:01
string and int and when we when there's also an implicit operator to two int so when we printed out console dot write line let me see where the hovering shows
52:21
what's going on yes it does right so if I hover over this probably shows two small c but it's showing that it's using console dot write line int even though the type of x isn't int there is an overload sorry there's a an implicit conversion to int and the overload that takes an int is more specific
52:41
than the overload that takes object which is the only other one available for this on the other hand when we use this form because we're using standard formatting this is now going to call to string it doesn't know that there is an int conversion
53:02
that was very impressively quick I have to say okay something slightly similar I have two bits of code that look very similar so we've got some mystery
53:20
class and we're going to call get value on it and it's dynamic we don't know exactly where this count method is going to come from but we're using system dot link so maybe that'll work demo two doesn't have system dot link so the count method had better be a method right
53:44
doesn't really matter exactly what the output is other than the fact that I'm running the wrong project when I do demo one it prints three when I run demo two it prints ten any ideas what can be going
54:00
on such that just adding using system dot link makes a difference lots of answers shout out because I can't hear details dynamic is a class as well where?
54:20
but importantly it's in the system dot link name space it gets a bit funkier than that so mystery is declared to is statically declared to return a system dot link dot dynamic so even though we don't have in demo one
54:40
demo two rather even though we don't have a using directive for system dot link it's declared to return a system dot link dot dynamic but we're just using dynamic the real dynamic so when we call x dot count it's really trying to find the count method which it finds
55:05
ba ba ba finds from here so we have one class called dynamic and then a subclass called static so actually in this case the static type of the return of get value is dynamic but the dynamic type the runtime
55:22
type is static just for a bit of fun so count returns ten and it finds that using dynamic typing in demo one we know about system dot link so dynamic here refers to the class but we've also got
55:41
an extension method the normal enumerable extension method so this is now calling the standard extension method because dynamic also implements i enumerable of int and we're yielding three things so even though we're not calling the the statically typed
56:01
thing is calling an extension method and the dynamically typed thing is calling the actual you know really known count method partly because dynamic typing can't call extension methods and partly because it knows that the type is actually static so that's a little bit of funkiness and I have four minutes to show wrapping async
56:21
this is a shame I'll probably keep you all a bit longer feel free to leave when you need to though right so let me give an example async is a sort of I think it might be called a como nad but async has something in common with normal link
56:40
and indeed with nullable of t they're all about wrapping and unwrapping so nullable of t I can write nullable int x equals ten and the compiler will wrap the int into a nullable int yeah and I can use an explicit conversion to unwrap it back to an int
57:00
in link we deal with one value at a time you know our select clause or where clause or whatever thinks of one value at a time and things are unwrapped and wrapped to deal with sequences in async not always to do with task but in general we'll think
57:20
of task you write code that deals with non-tasks by using await on a task to do unwrapping and then if you return a normal value you return an int and your method is declared to return a task of int the compiler does some wrapping for you that's all good until you've got multiple things
57:41
so say I've got a service that will give me multiple details about a person it will get me their weight, their name and their age their birth date each of those is going to be a task imagine I don't have a class that describes all of these things I can do
58:02
this but now I've got I've got to have these three variables and then separately create that and it's a bit of a pain I like this anonymous type because it wraps these related fields together imagine we had a tuple
58:22
instead of those tasks and we would like some way of unwrapping from a tuple of task T1 task T2, task T3 to a task of tuple T1 T2, T3 so it's sort of switching around the tupleness
58:41
and the taskness do you see what I'm saying? we can do that easily we can write our own little transpose method that basically says take these three tasks when they've all finished return a tuple
59:00
with all the results and this uses task completion source we could actually we could write this using async and just return a task of tuple T1 T2, T3 by awaiting all three so that's nice-ish we can then start doing it implicitly
59:22
by having an extension method on tuple task T1, task T2 task T3 called get a waiter so we have transposers the slow way of doing the explicit way of doing things and then if we call get a waiter we will just call transpose
59:42
and then call the get a waiter that's returned by the task async is pattern based for the await part therefore the compiler sees that tuple of task T1, T2, T3 doesn't have a real get a waiter method but it has this extension method so I'll call that instead
01:00:05
next, and I'm sorry I'm rushing this a little bit if we have an anonymous type and the nice thing about anonymous types and what I don't like about tuples is we get to see what these things mean wait, name, and birthday
01:00:22
have meanings item1, item2, item3 don't so tuple is kind of great for coupling things together