We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback
00:00

Formale Metadaten

Titel
Abusing C#
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
Herausgeber
Erscheinungsjahr
Sprache

Inhaltliche Metadaten

Fachgebiet
Genre
Abstract
We've all seen bad code. Code worthy of the Daily WTF. Code which makes us wonder how products ever ship, let alone work. Bad code is boring. Evil code is entirely different. It's bending a language in ways that would make the designers weep. It's code which you stare at and swear that it can't possibly work... until you see how it does.
31
59
Vorschaubild
1:00:41
89
Vorschaubild
1:00:33
90
Vorschaubild
1:00:33
102
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
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
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
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
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
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
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
XMLUML
Transkript: Englisch(automatisch erzeugt)
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.
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
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
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.
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?
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.
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
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
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,
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.
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
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?
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?
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
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.
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
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,
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.
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
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
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,
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
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,
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
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,
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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?
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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?
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
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
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
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
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
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
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
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
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
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
and that one takes event args so here we have a general one and we're going to do new
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
any ideas? hold that idea for later on but this is C sharp three to C sharp four
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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?
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
have meanings item1, item2, item3 don't so tuple is kind of great for coupling things together