Typed? Dynamic? Both! Cross-plat DSLs in C#
This is a modal window.
The media could not be loaded, either because the server or network failed or because the format is not supported.
Formal Metadata
Title |
| |
Alternative Title |
| |
Title of Series | ||
Number of Parts | 170 | |
Author | ||
License | CC Attribution - NonCommercial - ShareAlike 3.0 Unported: You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this | |
Identifiers | 10.5446/50873 (DOI) | |
Publisher | ||
Release Date | ||
Language |
Content Metadata
Subject Area | ||
Genre | ||
Abstract |
|
00:00
Computing platformSymbolic dynamicsEmailTwitterBlogPresentation of a groupSource codeTwitterGoodness of fitMultiplication signMachine visionFocus (optics)Computer animation
00:51
Software developerCategory of beingSoftware frameworkNumbering schemeComa BerenicesPhysical systemSynchronizationGroup actionMultiplication signComputer animation
02:19
DatabaseCompilerGrass (card game)Statement (computer science)Proxy serverSocial classFormal languageRegulärer Ausdruck <Textverarbeitung>Lambda calculusExtension (kinesiology)Type theoryFunctional (mathematics)Element (mathematics)Computer programmingWeightRevision controlPolymorphism (materials science)Image resolutionAdditionKeyboard shortcutFluid staticsSymbolic dynamicsAerodynamicsCodeCompilerClient (computing)Streaming mediaComa BerenicesRange (statistics)Cellular automatonSoftware frameworkEmailContext awarenessOvalReflection (mathematics)Axiom of choiceHybrid computerRun time (program lifecycle phase)Computing platformSet (mathematics)WordComputer fontInterrupt <Informatik>Object (grammar)Binary multiplierDatabaseRadical (chemistry)Formal languageTable (information)Category of beingLine (geometry)MathematicsSimilarity (geometry)Software developerImage resolutionSoftware frameworkCodeProgramming languageComputing platformSocial classComputer programmingCompilerComa BerenicesOperator (mathematics)Type theorySubsetSoftware testingDynamical systemWindowWeightLibrary (computing)Domain nameAxiom of choiceBoilerplate (text)HierarchyClient (computing)Enterprise architecturePhysical systemEmailFront and back endsAndroid (robot)Element (mathematics)Video gameProxy serverElectric generatorRevision controlFunctional (mathematics)Personal digital assistantFitness functionLink (knot theory)Exterior algebraComplementarityFocus (optics)Group actionExtension (kinesiology)Lambda calculusDependent and independent variablesProgramming paradigmImplementationOpen sourceSpecial unitary groupMixed realityWebsiteCondition numberMessage passingSystem callMereologyMultiplication signResultantScripting languageState observerExpressionArithmetic meanDataflowFunctional programmingBit rateAreaMassCollaborationismInterface (computing)Computer animation
10:13
Object (grammar)CodeAerodynamicsWeightService (economics)Default (computer science)DatabaseCore dumpClient (computing)Operations researchInterface (computing)Military operationSimilarity (geometry)Parameter (computer programming)Programming paradigmFunction (mathematics)Axiom of choiceReal numberServer (computing)Time domainLine (geometry)Social classLibrary (computing)Symbolic dynamicsExtension (kinesiology)Regulärer Ausdruck <Textverarbeitung>Constructor (object-oriented programming)Strategy gameHybrid computerPhysical systemSpacetimeType theoryComputing platformQuery languageLibrary (computing)Computing platformLine (geometry)ImplementationAxiom of choiceNumberSocial classService (economics)Interface (computing)Core dumpSymbolic dynamicsDatabaseOperator (mathematics)Real numberExpressionExtension (kinesiology)Power (physics)Single-precision floating-point formatSoftware developerDynamical systemNumeral (linguistics)Point (geometry)Exterior algebraBlock (periodic table)MereologyData conversionParsingLink (knot theory)LogicData storage deviceRevision controlObject (grammar)Structural loadCodePrisoner's dilemmaSystem callProjective planeHybrid computerPortable communications deviceFormal languagePhysical lawAreaType theoryPlastikkarteSet (mathematics)Client (computing)CountingMessage passingMultiplication signWeightOverhead (computing)Open sourceRight angleBounded variationException handlingDomain nameGame controllerNumerical integrationSelectivity (electronic)FamilyDifferent (Kate Ryan album)Resolvent formalismStrategy gameWrapper (data mining)INTEGRALInformation overloadSoftware frameworkQuery languageFluid staticsCompilation albumBitInstance (computer science)Computer animation
18:06
Symbolic dynamicsClient (computing)Observational studyHybrid computerSource codeImplementationLibrary (computing)Query languageRegulärer Ausdruck <Textverarbeitung>CoprocessorInternet service providerSubsetInterface (computing)String (computer science)BuildingRevision controlFile formatOrder (biology)Power (physics)Differenz <Mathematik>Data typeBlock (periodic table)InformationEquals signLoop (music)ChecklistProcess (computing)ParsingSurvival analysisNetwork topologyLogical constantNumberLambda calculusParsingFunction (mathematics)System callOperator (mathematics)Information overloadPerformance appraisalTime domainOperations researchField (computer science)Interface (computing)Social classRevision controlError messageCategory of beingLink (knot theory)String (computer science)BuildingSubsetOrder (biology)Slide ruleSyntaxbaumVertex (graph theory)Multiplication signFunctional (mathematics)Projective planeImplementationObservational studyNumberClient (computing)Lattice (order)Domain nameFocus (optics)Internet service providerMereologyBoolean algebraExpressionType theoryHybrid computerCompilerStatement (computer science)Logical constantReal numberChainData conversionMappingOpen sourceCodeDeclarative programmingQuery languageParsingPlanningAreaMathematicsCASE <Informatik>Communications protocolGeneric programmingNetwork topologyDynamical systemInformationReading (process)Representation (politics)OntologyTable (information)Selectivity (electronic)Condition numberOperator (mathematics)Extension (kinesiology)Single-precision floating-point formatCellular automatonSequelScaling (geometry)Streaming mediaGreen's functionSurgeryMachine visionSet (mathematics)System callDifferent (Kate Ryan album)Row (database)Goodness of fitComputer animation
25:59
Regulärer Ausdruck <Textverarbeitung>Information and communications technologyExpressionParsingRevision controlBuildingSoftware testingDynamical systemFunctional (mathematics)CodeSystem callCore dumpSyntaxbaumLine (geometry)Computer fileLink (knot theory)Right angleBinary codeType theoryMereologySequelSymbolic dynamicsProjective planeString (computer science)Slide rulePhase transitionComputer animationSource code
28:19
Interface (computing)ImplementationData conversionRegulärer Ausdruck <Textverarbeitung>Object (grammar)ParsingPerformance appraisalBuildingConstructor (object-oriented programming)Parameter (computer programming)Extension (kinesiology)Symbolic dynamicsCore dumpStrategy gameSpacetimeType theoryPhysical systemComputing platformClient (computing)Order (biology)AerodynamicsInternet service providerMeta elementRun time (program lifecycle phase)Keyboard shortcutAdditionCASE <Informatik>Link (knot theory)Electric generatorInheritance (object-oriented programming)MultiplicationTable (information)Object (grammar)2 (number)Revision controlSet (mathematics)Client (computing)Type theoryInformation overloadDynamical systemMereologyImplementationExpressionGeneric programmingCompilerOrder (biology)Social classData conversionWeightCodeSyntaxbaumInterface (computing)Electronic mailing listInternet service providerMeta elementLine (geometry)Operator (mathematics)NumberAxiom of choiceStructural loadMessage passingAreaAdditionSign (mathematics)Computer clusterPhase transitionSoftware developerStrategy gameGame controllerClassical physicsPhysical lawBuildingComputer animation
32:47
Portable communications deviceDrum memoryR-ParitätConstructor (object-oriented programming)Peer-to-peerSymbolic dynamicsParameter (computer programming)Information overloadSmoothingOperations researchCodeClient (computing)AerodynamicsoutputObject (grammar)AbstractionInterface (computing)Extension (kinesiology)Data dictionarySingle-precision floating-point formatCoprocessorRegulärer Ausdruck <Textverarbeitung>Data conversionResultantRow (database)Client (computing)CASE <Informatik>Object (grammar)Library catalogInterface (computing)String (computer science)Software testingSymbolic dynamicsDynamical systemBuildingCoprocessorMultiplication signFormal languageType theoryMereologyExpressionLevel (video gaming)DatabaseProjective planeTerm (mathematics)Line (geometry)Keyboard shortcutFunctional (mathematics)Social classRevision controlExpected valueContent (media)Data conversionInformation overloadExtension (kinesiology)Ferry CorstenException handlingTable (information)Service (economics)Statement (computer science)Execution unitPosition operatorNumberCompass (drafting)Coma BerenicesData streamImplementationReflection (mathematics)Boss CorporationPositional notationDecision theoryData dictionaryNatural numberVarianceWrapper (data mining)Similarity (geometry).NET FrameworkMessage passingCodeQuery languageWindowPortable communications deviceLibrary (computing)Dynamischer TestLogical constantDomain nameHybrid computerComputer animation
40:23
View (database)MaizeCoprocessorInformation overloadObject (grammar)Generic programmingCore dumpAerodynamicsExtension (kinesiology)Library (computing)Computing platformConstraint (mathematics)Windows PhoneWeightAndroid (robot)ExpressionObject (grammar)Fluid staticsPortable communications deviceData conversionExecution unitDynamical systemKeyboard shortcutResultantComputing platformType theoryRow (database)Client (computing)String (computer science)Modal logicDatabaseCategory of beingWrapper (data mining)Extension (kinesiology)Matching (graph theory)Demo (music)Point (geometry)WordData typeLibrary (computing)Cross-platform.NET FrameworkCASE <Informatik>Control flowUnit testingProjective planeRevision controlProcess (computing)Personal digital assistantForm (programming)Coma BerenicesMessage passingGreatest elementQueue (abstract data type)Single-precision floating-point formatMusical ensembleComputer animation
43:55
WordCross-platformComputer animation
44:46
Demo (music)Software testingSymbolic dynamicsView (database)MathematicsPoint (geometry)Visualization (computer graphics)Computer animation
45:29
Software testingBuildingForm (programming)2 (number)Boss CorporationWindowObject (grammar)Android (robot)Computer simulationComputer animation
46:18
Software testingDemo (music)AerodynamicsKeyboard shortcutFluid staticsComputer programmingSoftware developerAxiom of choiceType theoryCompilerSocial classProxy serverError messageCodeRun time (program lifecycle phase)Network topologyCore dumpRegulärer Ausdruck <Textverarbeitung>Constructor (object-oriented programming)Parameter (computer programming)Extension (kinesiology)Symbolic dynamicsHybrid computerStrategy gamePhysical systemSpacetimeComputing platformTwitterBlogPresentation of a groupSource codeTouchscreenComputer simulationSoftware testingWeightAsynchronous Transfer ModeDynamischer TestType theoryPhysical lawLibrary (computing)Link (knot theory)FamilyGame theoryBounded variationAreaExpressionVideo gameNumberProper mapNetwork topologyProjective planeClient (computing)Line (geometry)Point cloudGreatest elementCore dumpCoefficient of determinationBranch (computer science)Arithmetic meanMultiplication signSyntaxbaumSocial classHybrid computerCodeAssembly languageCartesian coordinate systemError messageMachine codeExtension (kinesiology)Symbolic dynamicsProxy serverComputing platformComputer animation
54:06
Software developerComputer animation
Transcript: English(auto-generated)
00:02
Good afternoon, everyone, and welcome to the last talk of the last day of the conference. It's Friday afternoon, so I appreciate you coming here. And today, we're going to talk about some aspects of API design. My name is Swagiv. I work for Norwegian company Miles.
00:24
I'm originally from Russia, but have been living in Norway for over two decades. You can find me on Twitter, you can mail me if you have any questions, and if you find interesting what I'm going to talk about, please check out the GitHub repository, which contains everything I will show you, plus some extras.
00:44
So our focus this hour is some aspects of API design in modern times. Who was at James Newton King's session about API design yesterday?
01:02
Okay, looks like I was the only one. Okay, that was a great session about focusing on how you design API in a way that developers feel at home, like they feel familiarity with the way they used to work. James also recommended a book which has become a classical book from 2008,
01:24
Framework Design Guidelines, but looking at this book today, I find that some of the recommendations, they have to be taken with care. For example, just to give an example, it recommends use of lazy values.
01:45
You have something like get schema, and then if you have property schema, it's lazy property, which just read on demand. But with modern APIs, if you are careful about asynchronous calls, then you have to be very explicit about what and how you fetch.
02:03
So actually lazy doesn't play very well with synchronicity. And there are other aspects of that. So modern times API come with some additional precautions to make it both consistent and flexible.
02:20
And this is not easy. It used to be much easier 10 years ago. If you had to choose framework and main programming language for development 10 years ago, and if it was C sharp and .NET, there it had to be object oriented programming with class hierarchies and interfaces,
02:41
and of course, strong types. So it was a relatively narrow window of opportunities comparing to modern types. And nowadays, when people write mission-critical backend systems in JavaScript, of course, this can't get unnoticed in traditional platforms.
03:03
So even though if you're doing enterprise development in C sharp .NET, you will be influenced by that. And it's not just a conflict of generations when the father has been doing all his life J2E enterprise programming, and the son is hanging with some Ruby youngsters.
03:21
The choice is more complicated and maybe more confusing because this happening to the same language, to the same platform, which is traditional in a way for us. First, C sharp was extended with elements of functional programming, and it happened around 2007.
03:44
It was driven by link development, and it spawned such innovations like lambda expressions, extension methods, all these fits very nicely in functional paradigm. But it didn't actually create a kind of conflict with traditional development.
04:02
It came as a nice complement. But what happened in 2010, when the language and platform has been extended through so-called DLR, dynamic language runtime, in many scenarios, well, at least in some scenarios, created some alternatives to a traditional way of doing statically bound class resolution.
04:26
So suddenly we could start writing code and compile it and take any responsibility about how this code will be resolved. So suddenly it was possible to write absurdly looking code.
04:43
As long as you wrote a word dynamic, compiler kind of washed his hands. And that affected not just properties and methods. As you can see, here you can mix apples and oranges. So you can multiply grids by integers, and as long as there is dynamic object involved in the operation, compiler doesn't care.
05:06
So needless to say that that was met by some skepticism by some developers. And first examples that Microsoft published on MSDN documentation website, there were rather minor improvements.
05:22
Like here, you can get rid of typecast when it comes to com interrupt. And you can say that the second example is nicer looking because you don't have typecast, but some developers would argue that the code is also deceiving, because it actually looks like it's compiled, statically compiled code, but actually it is not.
05:46
But soon developers brought more radical changes to all that. And they started using dynamic programming to gain greater achievements.
06:03
So if you look now at how dynamic library simple data is used, you can see that the whole API looks like it's written specifically for our domain. You have database with property users, with method find all by email,
06:22
and of course there is no such properties, there is no such method. So what simple data does is that it talks to the database, and it pretends that there are such methods and properties, as long as there is a table users in the database, and there is an email column in such table,
06:40
and the rest are just conventions. And it's also smart to convert it back to user entity. But you didn't actually have to declare the entity detail, because you could just send back dynamic object, as long as client would accept it. And here, this example demonstrates even more radical code saving,
07:05
not just saving on DTO and some proxy generated classes. Everyone working with acceptance test development in .NET or BDD, of course recognized as Gherkin language, and underneath is so-called step implementation using specflow.
07:25
But these two lines, they can replace maybe 50 or 100 lines of boilerplate code, because if you had to write this code yourself, you would start parsing this table and extracting values, and then you have some DTO, and you put these values there,
07:42
then you have data access layer, and maybe another DTO, you have to have adapter, maybe use automapper, and so on. So it's not creative work. Here, two lines of code, actually taken from two different libraries. The first one is simple, sorry, specflow assist dynamic,
08:02
and the other one, again, is simple data, and they interoperate nicely. So obviously, there is a great code saving, and that was convincing for dynamic libraries to stay in the static code world. So popularity of dynamic libraries is growing,
08:24
and you can see just some examples from various areas, some very successful examples, SignalR, Nancy, SimpleData. There are other database micro ORM, like Massive, for example, ez-http, you see they cover different areas,
08:40
and they really save us on code typing. So I'm not going to answer the question whether you should use dynamic libraries, because this talk is about different things. We are putting the hat of API designer, and trying to answer different question, how to actually reach out wider group of developers,
09:04
and some of them may prefer dynamic API, some of them prefer static API. And then, right now, you have to choose, basically. If you like to consume database classes using dynamic API, it must be Massive, SimpleData, or something similar.
09:24
Otherwise, it could be Hibernate, and Hibernate on the framework. But our focus is to expose a single API in a hybrid way. So you can write both dynamic and statically typed clients,
09:40
which will talk to the same operation set. And we'll also look at how it's best to package this API, because what we're going to show is actually cross-platform library, which can work even on iOS and Android devices using Xamarin tools. And not all platforms support dynamic,
10:01
like Silverlight 4 doesn't support dynamic, Windows font 7 doesn't support, and iOS only has experimental dynamic support, which in practice means that it's not supported. I tried that. So you have to be selective. So how can we package it in a way that it can be deployed smartly? So having said all that, just on a side note,
10:25
the choice of going for dynamic, use of dynamic typing in your C-Sharp code depends, ironically, maybe not on external interoperability, because dynamic languages are very good,
10:42
and dynamic C-Sharp is very good in implementing interop with external services. But ironically, again, the internal interop with statically typed C-Sharp is not always smooth. Just to give you a simple example, if you consume a lot of data using dynamic C-Sharp in collections,
11:02
you would expect to be able to use link operations, but link operations like single, first-to-default, count, they all come as extension methods, and extension methods resolve at compile time, which means that they can't be applied to dynamic objects. It will result in write-time exception. So you will have to explicitly cast as an enumerable of dynamic, for example.
11:22
So if you have a lot of such integration points, internal points, they can become pain points. So bear this in mind. But if you properly arrange where dynamic blocks can be used, you will have great code savings, as we saw in a few examples.
11:44
So we'll use database access as our main domain, because this is something that everyone understands. So this is database access code written using link, using Fluent API.
12:03
And this can be an alternative written using dynamic API that we have methods find by company name, select company name in a year. So we will simulate domain, ubiquitous language in a way,
12:24
or domain entities at least. Alternative to that is that we actually expose the same operation set. So if you talk about database access, there will be where, select, or the by and so on. And we will differentiate inside these operations
12:42
by implementing several overloads, so both dynamic and static clients will work. And of course the choice of API style is very opinionated question, because as an API designer, you probably have some strong feeling about how it should look.
13:01
But those who were on this James Newton King talk, and apparently it was just me, but those who read this framework guideline book, may recall, there was a phrase coined by Brad Adams, one of course of this book, the power of sameness.
13:21
So the sameness, like operation sets or different APIs looking the same, give you some power. So the question is not choosing the style for your API, the question is, do you want to expose two APIs, dynamic and static ones, or just one?
13:42
So what I will try you to convince is that the single API set will give you better visibility to reach out wider development group, relating themselves just to single API.
14:01
So we will have some API common core, and the simplified version of the interface will be like this, so this method can be changed. And we will implement something smart inside, so both dynamic and static clients can use that. So with one API, two paradigms.
14:23
So you see these two code examples, they look similar. In fact, dynamic version looks a bit short, at least in the actual calling part, because you don't need to specify lambda expressions, you just write directly dynamic expressions. But you need to define this expression object somewhere,
14:43
and it can be just once for the whole application, because this is not real storage, you will never need to persist it. This is just used to send to methods and convert, do some conversion. So this is our approach, exposing single API. It can be consumed in that way.
15:02
One question which I already received, is what about the extra cost? Do you need to implement a lot of stuff if you do it that way? So this talk is actually based on a real-world project. There is an open source library called Simple Data Client that is a hybrid API.
15:21
It's a portable class library, which supports both dynamic and static calls. And the dynamic wrapper, it took six classes and 59 lines of code. When I was working on examples for this talk, I actually did more, did better support in the dynamic wrapper, so it took me 76 lines of code.
15:41
But what I'm trying to say is that the overhead is pretty much fixed. You just implement some magic in your dynamic wrapper, and that will be the same number of lines of code almost no matter what DSL you are exposing. There may be some variations,
16:00
but the core part is the same. So there is no dual implementation, there is no re-implementation. You will never repeat yourself when working with these libraries. So this is our strategy for a hybrid API. What we are going to do is we will package our domain logic in statically typed library,
16:26
and we will expose just statically accessed methods. We will use link expressions, because it gives your DSL very good expressiveness.
16:42
And this link expression we will parse and store in some custom expression. Then we will add a small wrapper, which will be dynamic wrapper, where we will subclass our custom expression, so our dynamic calls will be sending
17:01
this subclass instance of expression, which will be converted into the custom statically typed expression, and the actual execution is fully statically typed. So, just to give an example of,
17:22
a simplified example of implementation and packaging. So you have some library finder DLL, which will work on all platforms supporting modern .NET, which will have interface iFinder, and there will be two overloads,
17:40
find which takes link expressions and find which takes this custom expression, that's called query expression. Users will never have to think about this overload, they will never relate themselves to some explicit choice of this, it will just happen to them. But the second overload will actually be used by dynamic wrapper
18:01
that will send their subclass version of this query expression. So this is how it will work. And then the client code might look like this. So in statically typed client, we instantiate our finder, and we send link expression to it.
18:21
And by the way, our link expression parser, it's pretty much how it works also for real world link expression parsers. So actually it's not a very long way to go from that implementation to have a link provider. Of course you will have to implement things like iQueryable, deferred query execution,
18:41
but the actual tree parsing is there. And then dynamic client looks similar, again you just need to declare dynamic query expression and you can send it around using almost the same syntax and it will be converted to the same link expression. So plan for the rest of the talk
19:02
is go through the case study. We are going to work with SQL commands, which of course everyone understands what it is. As I mentioned earlier, so the implementation just extracted part of open source project
19:21
with changed domain area because all data protocol is not something that everybody is fluent in. And we will incrementally grow our implementation until we see it works for static client, dynamic client, and even mobile clients. So our case study is hybrid SQL command builder.
19:43
So as you probably have understood, we'll be writing something like link provider. And this is traditional link statements using different syntaxes, both supported by C Sharp compiler. We'll focus on the second one, on the fluent syntax.
20:04
And this is a supported subset of SQL commands. It will be, of course, shorter, smaller subset than real SQL. There will be no join, but there are no principal difficulties to implement stuff like join. It just requires more work, but the design part is the same.
20:25
Just to give you a quick idea of the scope of our work, if we were dealing with hardcoded strings, our untyped version of command builder might look like this. So this is interface that takes some magic strings,
20:42
which nobody likes, chain them, and then we call build, and in this build operation, all the strings can be concatenated together and the build final command. And the command class will have, again, string fields for tables,
21:01
for condition, for selection, and order by columns. And the actual building command is really simple, and anyone would probably implement it in a quarter of an hour, because you see that's the whole code. It's just string concatenation
21:21
and list concatenation. So we will get this subset of support of SQL commands. So moving on to typed version. So now we need command builder of T. And in order to get command builder of T,
21:42
we'll need to inject somewhere T. So we'll have two interfaces. First one is non-generic one, where we will be sending the actual T, which may be companies or persons of our entity set, entity class. And this command builder, non-generic one,
22:01
will give us generic one. And from there, we can send generic link expressions. So this is a typical usage example. We'll get instantiate command builder, and then we'll run right from companies. At that time, we're getting typed version of command builder.
22:22
So we continue then with X, which is X of companies. So we can choose any properties of X of companies, and everything will be statically compiled. So if you write something that doesn't make sense,
22:41
we will get compiler error. That brings us to link expression trees. And this slide lists the number of link expression tree nodes, which is exactly 84. And of course, it gives a question, do we really want to do that?
23:01
Who works with parsing link expression? Well, I have full understanding for that, because it really looks scary. In fact, when you start working with it, it's not that scary. There is a lot of open source code around, which you can use as example.
23:20
And my project is also at GitHub. So if you use some time on it to make ends meet, then in return, you will get very good expressiveness, because in many cases, the DSL that uses link expression trees
23:44
is much better to express your intent. Previous talk was about Elasticsearch, and of course, one of the examples of them was link provider for Elasticsearch,
24:00
because whatever search type you implement, link will work very good. And it doesn't have a need to be search. Most of the things which we are doing, a lot of it, it's getting some typed data using some criteria. So link expressions are very good into implementing that. This is an example of a link expression tree,
24:23
which probably shows why there are so many nodes, node types. So above, you will see an example of a link expression, and this is how it's represented internally. So there are 12 nodes, and four of them leaves, and you start from Lambda, then go to end,
24:44
which is actually called end also, greater than, less than, member access, which member accesses to access properties, constant, to access constant values, which are in red, and so on. So it actually makes a lot of sense
25:03
once you start digging into it, and there are some things to remember. One of them is that you will probably want to convert C Sharp functions to your DSL functions. For example, if it's SQL,
25:20
you will want to support stuff like Len in SQL, which corresponds to string length. In C Sharp, you will need some function maps. You will need to interpret operations. So you will have to plan to list all supported operations, functions in your DSL,
25:42
and then map from link expressions how you would interpret them. You don't need to support everything. You can just throw exceptions if you're not supporting them. So just to give you a little insight about how this can work,
26:02
so this is an example of the project. Okay, and go to solution. I will probably need to, yeah, to the solution, and you see this SQL command builder. This is typed version and tests.
26:23
And you see most of the typed version is about expressions, how to deal with them. So if you look at function mapping, for example, these are my functions. On the left side, you see C Sharp functions and how I map them to SQL.
26:41
The core of the actual expression parsing is that I go through this. Here I manage my expression trees. So parse member expression, parse call expression. So yes, this file is about, I guess, 150 lines of code.
27:02
But if you see what happens when we try to debug the tests, you will soon get a picture of what's happening. So here we have where expression, and this is expression x company name equals dynamic soft.
27:24
So what we can do, we can step in. We're stepping in, parse link expression. Okay, parsing begins. Not type, this is a binary expression. So we're parsing binary expression and so on. So left expression here is company name,
27:42
right expression dynamic soft. So we just continue that way until everything is parsed. And then we reach the build phase. Here actually we have a command already built because I overloaded two strings, so now it actually shows what we will get.
28:01
But here is the build there. And it's more or less what I showed in that slide. We have string build and we just concatenate strings. So the most demanding thing, of course, is link expression parsing, but it's a very powerful thing. So if your DSL is rich enough to justify this work,
28:22
I really recommend to have a look at that. So this is typed command builder workflow. So we take from and some table name. We assign the type and generate generic builder. Then we assign where expression. And we convert it to our custom expression,
28:43
which is command expression, and we build. So we actually, we are halfway through. So now we have a typed command builder. So now the interesting part, how we add something to it, so it will magically consume dynamic clients.
29:03
So what is left now is, if you look at typed command builder, you remember that stupid examples of using dynamic object, which I showed you, that you just typed the word dynamic and then compiler doesn't care. So you actually, you can send your dynamic objects right here
29:22
and compiler won't care. They will compile, but they will fail because the challenging part is that nobody knows how to map your dynamic expressions to link expression trees. And the solution to that, if you implement overloads
29:45
for your interface, which will also take not just link expression because we don't have control over .NET expressions, but it will also take overloads, which will take our command expression.
30:00
So this code will become possible. So let's recall our strategy, and we are somewhere in between. So now we are about subclassing our custom expression. But before we do that, we need to enhance our command builder.
30:20
So we start overloading methods. So our first non-generic command builder had only one method. Now it has two, and the second one takes command expression. The same goes for generic command builder. You see the number of methods doubled, but the operation set is still the same because these are just method overloads.
30:42
We as developers, we never care how many method overloads certain interface or class has, as long as everything happens for us smoothly and we don't need to explicitly make a choice. So where will have two methods. So type client will use the first one,
31:00
and dynamic will use the second one. And it's compiler who will make a choice for us. The same goes for order by, the same goes for select. And you can see that in case of order by and select, the overload actually takes an array of command expression. So we can write a list of dynamic expressions
31:21
and compiler will choose that overload. And adding method overloads and implementing them actually is trivial because our original typed version already includes code which is shown on the first method implementation.
31:41
We take link expression and we convert it to our custom expression. And since in case of dynamic client, it's the second overload invoked, we should already take our command expression. We don't need to do anything. We just assign it to our, send it to our command. What is less trivial is to add this conversion magic
32:04
because we have to convert this dynamic expression stuff into our command expression. And usual or traditional implementation of dynamic objects is to subclass .NET built-in dynamic object helper.
32:20
It won't work for us because we want to subclass command expression and C Sharp doesn't support multiple inheritance. So what we'll need is to implement interface I dynamic meta object provider. And then we can subclass our command expression. But believe me, it's not much more lines of code,
32:44
which I'm going to show you right now. So if you look at dynamic version, which is the project here. Yeah, so there is a, just to enlarge it.
33:00
So this is the old, like first typed version, is almost untouched. We just needed to add some overloads for interface. But there is a new project here, SQL command builder dynamic. And by the way, if you look at what it supports,
33:21
you see that it supports .NET framework 4, so we add 5, Windows 8, Windows 4, so we add 8, Xamarin, Android, Xamarin, iOS. Well, when it works on iOS, finally. Currently, it won't work on iOS, but support is already there. So it's a portable class library. And if you look at the content of it,
33:42
it's those 76 lines of code which I mentioned, which basically what they do is they implement some binding functions, bind get member, bind set member. What these functions do is whenever there is dynamic expression coming to us, CLR gets lost.
34:01
Okay, there is something dynamic. How would I deal with that? We have to answer this question. Okay, I recognize that, and I return this, and we return our typed object. If we don't answer this question positively, then exception will be thrown. So let's have a quick look at unit tests,
34:22
and then the same test we will run in debugger, in dynamic version. Let me see. Okay, it's type test. I have to run dynamic tests. Yeah, so it stops here, bind get member,
34:41
and here we have some binder. Okay, what is binder? Yeah, and you can probably see it here, and if it's too small, I can tell you that this says companies. So we have a binder with a member companies, which means that there was some statement
35:02
which says x.companies, and then they are, and CLR, they get both lost. So we have to say what to do with that. So what we're doing here is that we create expression constant from binder name. So we convert it to our custom expression
35:24
based on binder name. So we continue doing that with all other expression that we receive, and then we see that the test passed. So there is a very small chunk of code
35:41
where we implement the handling of incoming expressions, and it's a relatively inexpensive thing. So you just have to interpret according to domain language. You might check a catalog of your database tables, for example, and throw exception if you find something that you don't encounter.
36:07
So, and in case of dynamic command builder, the last part is just follow typed builder workflow, but we begin from a different place. We start from dynamic expression,
36:22
we try, compile selects as command expression based overload, and we do conversion, and then we continue just as it was type command builder. Are we finished? Well, we are finished with SQL hybrid command builder,
36:42
but there is one other aspect of this. How should we deal with return values? Because when we're sending data in, it's understandable. We have some expressions, we map them, convert them, and then we have this hybrid API. But what if we have dynamic clients and type clients?
37:00
And type clients will expect types of companies and while dynamic clients will expect some dynamic object. And to show how this can be done, I extended this project with command processor, which is very simple. It just has a couple of methods, find one and find all.
37:24
And this is how it's used, in typed version and dynamic version. So, and apparently, there are some extra extensions to our dynamic wrapper we need to add.
37:42
Both for returning typed results and for returning dynamic results. First, for returning typed results. If we want to convert whatever execution engine returns to us, we need to have some extension method that will map it to our NC object.
38:01
Because whatever database engine you're using, it's doing its work using some internal data. If it's MongoDB, it will be BSON. If it's SQL Server, it will be a table of data streams. But it doesn't know anything about your types. So you will have to do some work. And this is done by implementing reflection-based conversion.
38:25
So I have a couple of extension classes to object of T, which actually fixes that. And so I can get companies and collection of companies when I send and execute the query related to retrieving companies.
38:42
Unfortunately, this is not sufficient for dynamic clients to be as smooth as typed clients. Because if I don't have any typed objects in my dynamic client, then I will get some dictionary of string of object or whatever internal type my execution engine operates with.
39:02
And also, I would like to be able to fluently convert to typed versions from dynamic client. So in a similar way, with command builder, we have command processor that has overloads.
39:21
And instead of returning raw data, we encapsulate our results in result row and result collection. And we also introduce dynamic result row, dynamic result collection. And likewise with command builder, for clients, it's all unnoticed.
39:41
Clients will just use them as everything flows naturally. You can see here that dynamic client is now fine. So you can get dynamic results. You have var result, which will probably get dynamic object.
40:03
And you have also typed result. And what will happen is that our dynamic wrapper will again call another bind function to try to convert it to whatever type we supply.
40:21
So just to give you a quick insight on how this might work. So I'm now on this project. And if I look at my dynamic projects,
40:40
you will see that there are three classes. We used to have only dynamic command expression. Now we have dynamic result collection, dynamic result row. And this is because we need to implement these small conversions. If you look at dynamic result row, for example, you will see there is a method bind convert.
41:03
So what happens is that when there is an attempt to convert dynamic object back to static type word, to company or collection of companies, we will get a method called here saying, okay, this is a request to bind, to convert.
41:24
I can show you actually with some unit tests. Let me see. Here dynamic test and execute, find one S type. So this probably should hit that break point.
41:43
Yeah, it did. So there is a binder here. And you can see that the binder says return type companies. So this return type is completely unknown to us. So we get a request. Somebody is trying to cast your dynamic object to companies. And we can, since we have a type,
42:01
we can check what properties we have there. Maybe it's a good match. And if we receive from the database stuff with name, first name, last name, and there are matching properties in that type, we will try to convert.
42:22
So type command processor workflow is simple. You're sending command as before, but you're also trying to get results back. So we execute processor, get results,
42:43
and then we have some internal data type. In this case, add diction string of object, just for demo purpose, which is converted using some extension method to object of T. And in case of dynamic processor, there is a conversion to object of dynamic result collection.
43:02
And then there will be hit bind convert method in our dynamic wrapper to convert it to other types if necessary. A couple of words about cross-platform portability. As I said, these libraries, I implemented as portable class libraries
43:21
and work on all modern .NET platforms. And they don't have any other external dependencies. So they are just raw and can be used as example of how you can implement this stuff. Of course, legacy platforms are out of the picture
43:40
because they don't have support for dynamic stuff, but you can use typed version and deploy it on Civilite for clients. So you can be selective with what you deploy on each platform. Just to give you, let me see, idea of how it might work here.
44:04
Here I have, oops, what happens? Well, do you see anything?
44:22
Sorry for that, but I, excuse me, I may need some help. Okay, it's coming something. Okay, yeah. Yeah, you know, it probably heard the word cross-platform.
44:45
So then it gets scared. I wonder why it's that. Okay, let's try anyway. So I want to deploy it on, hmm, that is strange.
45:00
Can it be something with a cable? No, it just keeps resizing things. So if we go back to SharePoint, it works fine.
45:23
If I go to Visual Studio, okay, try to deploy. So what I'm doing now is I'm deploying it to the Android simulator.
45:42
I also have Windows Phone and iOS. Okay, it's deployed. Yeah, probably while you're here, it works better. But hopefully it will work. Okay, SQL command build the tests. So let's start it, and it will start in a few seconds, run test.
46:02
So this is just a small test approach. I just learned a test runner, which runs tests. And both typed and dynamic, and there are 28 tests passed. I've also, the same I did for Windows Phone and for iOS.
46:23
I will not take chance on running our simulator now, because then I have to switch to native mode on Mac. So I just, you have to believe me. This is a screenshot. I haven't made it up. It's just a real screenshot. But you will see that there are a few tests, because I had to exclude all dynamic tests.
46:41
But typed tests work. So this stuff is proven on all modern .NET platforms, as long as dynamic is supported. So conclusion. Yes, it takes some extra effort to design API properly. But if you really want expressive API,
47:04
you will find that benefits will outweigh, or may outweigh, some extra effort. And also, as you saw, the number of line of codes you need to reach both dynamic and typed clients
47:23
is really not that big. So if you have a library that can be exposed for dynamic clients, I would recommend to use this approach, which doesn't need to work with link expression trees.
47:42
You can actually create your own classes. But with link expression trees, you gain some additional expressiveness. So the moral, make hybrid API and not hybrid war. And while we have a few minutes to go, since it's now Friday and it's late,
48:03
so I want to give you a little boost. And I invite you to sing along with me a karaoke song about the material which we have just gone through. So this is inspired by a song by Queen.
48:20
I'm going slightly mad. Of course, if you have a song with such lyrics, you can tweak it to sing about anything. And it's a new variation. It's called I broke my static types. I'll try to sing like Freddie Mercury.
48:53
When compala acts rough and ruthless And the meaning is also clear
49:01
One thousand and one nasty errors Begin to dance in front of you, oh dear Are they trying to tell you something? Your proxy classes are out of date Or you made your code with the wrong branch
49:22
Or maybe it's just getting
49:43
It finally happened It finally happened
50:15
Can't sleep For the drum time
50:20
It finally happened
51:18
You implement your dynamic extensions
51:20
In a different assembler On the platforms that support And then everything will go fine
52:10
Dynamic code
52:47
Great weekend and bon voyage If you came from a different place Thank you I'm probably open for some questions
53:05
If you have any Does it feel something that you might Applicable in your projects with some DSLs?
53:26
If you find something, take contact with me And I will try to help you out