SlideShare une entreprise Scribd logo
1  sur  81
Télécharger pour lire hors ligne
Building

    DSL         s
on the CLR and DLR
VitalyBaum
                          vbaum@live.com
                          butaji




MaximMoiseev
maxim.moiseev@gmail.com
                moiseev
http://altdotnet.org




http://spbalt.net/
The short annotation

DOMAIN SPECIFIC LANGUAGES
Domain Specific Languages (DSLs)
are limited forms of computer language
designed for a specific class of problems.
Martin Fowler
    “(DSL) is a computer language that's
targeted to a particular kind of problem,
 rather than a general purpose language
     that's aimed at any kind of software
                               problem.”
Paul Graham
“*Lisp Programmers+ follow a principle
which could be called bottom-up design--
changing the language to suit the
problem.”
DSLS CLASSIFICATION
Types of DSL

         Internal                   External
• Written in host           • Separate to host
  language                    language
• Conventional use of       • Needs the
  subset of host language     compiler/interpreter to
  syntax                      execute
Types of DSL

         Internal                    External
• Tied to base language   •   Lack of Symbolic
• Awkward with                Integration
  mainstream              •   Complex
                              parser/generator
                              technologies
                          •   Ignorant IDEs
                          •   (language cacophony)
Types of DSL

           Internal                  External
•   LINQ (C#)              •   Regexp
•   Monads (Haskell)       •   SQL
•   Workflows (F#)         •   CSS
•   Sequence expressions   •   Ant
    (F#)                   •   XSLT
•   List comprehensions
    (Haskell, Python)
Types of DSL
Graphical DSL
              Log
Workflow    Activity


             Clear
            Activity


           Shutdown
            Activity
DSL Oriented .NET Languages

LANGUAGES
F#       Ruby
     Lisp
                 Python

 Boo

C#
                 Smalltalk
F#       Ruby
     Lisp
                 Python
CLR
 Boo                DLR
C#
                 Smalltalk
I <3
The important advantages over a GPL

WHY SHOULD WE USE DSL?
Why should we use DSL
• Domain-specific abstractions: a DSL provides pre-
  defined abstractions to directly represent
  concepts from the application domain.
  Consequently, domain experts themselves can
  understand, validate, modify, and often even
  develop DSL program
• Domain-specific concrete syntax: a DSL offers a
  natural notation for a given domain and avoids
  syntactic clutter that often results when using a
  GPL.
Why should we use DSL

• Domain-specific error checking: a DSL enables
  building static analyzers that can find more
  errors than similar analyzers for a GPL and
  that can report the errors in language familiar
  to the domain expert.
• Domain-specific optimizations: a DSL creates
  opportunities for generating optimized code
  base on domain-specific knowledge, which is
  usually not available to a compiler for a GPL.
Why should we use DSL

• Domain-specific tool support: a DSL creates
  opportunities to improve any tooling aspect of
  a development environment, including,
  editors, debuggers, version control, etc.; the
  domain-specific knowledge that is explicitly
  captured by a DSL can be used to provide
  more intelligent tool support for developers.
Why is DSL good?

              Business
             Peoples and
               “Rules”



Developers
 and their
 “Magic”
Read                          and          Write
            director of finance for the client bank to edit, test,
and deploy the business rules of the system without any assistance from IT
Read   Write
DSL Building Patterns

PATTERNS
Better code readability

•   Fluent interfaces
•   Extension methods
•   LINQ
•   Workflows
•   Syntactic sugar
•   AdHoc LINQ
Fluent interfaces
Expect
  .Once
  .On(…)
  .Method(…)
  .WithAnyArguments()
  .Will(
       Return.Value(…)
  )

                           NMock mocking library usage
Fluent interfaces
Expect                   public static Expect {…}
  .Once                    IRecieverSyntax
  .On(…)                   IMethodSyntax
  .Method(…)               IArgumentSyntax
  .WithAnyArguments()      IActionSyntax
  .Will(
       Return.Value(…)     IAction
  )
Fluent interfaces
public class ExpectationBuilder:
  IReceiverSyntax,
  IMethodSyntax,
  IArgumentSyntax,
  IActionSyntax {…}

public IMethodSyntax On(…){
  // …
  return this;
}
public IArgumentSyntax Method(…){
  // …
  return this;
}
Combinations



today.at 3.pm
3.days.from_today at(3.pm)
Timespan Literals

print(50s) // 50 seconds
print(1d) // 1 day
print(2m) // 2 minutes
print(42ms) // 42 miliseconds
print("Tomorrow this time will be: ${date.Now +
  1d}")
String interpolation



print("Now is ${date.Now}.")
print("Tomorrow will be ${date.Now +
  1d}")
Extension methods

DateTime now =
                       VS   DateTime res =
   DateTime.Now;              3.Days()
TimeSpan span =               .From(
   TimeSpan.FromDays(3);          DateTime.Now
DateTime res =                )
   now + span;
Extension methods
public static class MyExtensions {

    public static TimeSpan Days(this int i) {
         return TimeSpan.FromDays(i);
    }

    public static DateTime From(
         this TimeSpan span, DateTime dt) {
         return dt + span;
    }

}
Man, there’s LINQ already
      Can’t we use that?
We do
LINQ
string s1 = GetS1();            VS var res =
string s2 = GetS2();                    from a in GetS1()
string res =                           from b in GetS2()
    string.Empty;                      select a + b;
if(s1 != null && s2 != null){
    res = s1 + s2;
}
LINQ
public class Maybe<T> {

      public T Value { get; private set; }
      public bool HasValue { get; private set; }

      private Maybe() { HasValue = false; }

      public Maybe(T value) {
        Value = value;
        HasValue = true;
      }

      public static readonly Maybe<T> Nothing = new Maybe<T>();
  }
LINQ
public static Maybe<T> ToMaybe<T>(this T value) {
  return new Maybe<T>(value);
}

public static Maybe<U> SelectMany<T, U>(
         this Maybe<T> src, Func<T, Maybe<U>> f) {
  if (!src.HasValue) {
         return Maybe<U>.Nothing;
  }
  return f(src.Value);
}
Important

• LINQ is a Monad
• F# Workflows are monads
• What isn’t?!

 "[W]hen the designers of F# talked with the designers of Haskell about this,
 they agreed that the word monad is a bit obscure and sounds a little
 daunting and that using other names might be wise.“

                          [F# Workflows and Haskell Monads, Expert F#, p232]
C# is no fun.
Want more!
Yeah?! F# you!
Workflows
type Чо<'a> =
  | Ничо
  | Чото of 'a

let bindMaybe x f =
   match x with
   | Ничо -> Ничо
   | Чото y -> f y

type MaybeBuilder() =
  member x.Return(what) = Чото what
  member x.Bind(m, f) = bindMaybe m f

let чокак = new MaybeBuilder()
Workflows
let first =
   чокак ,
      let! x = Чото 6
      let! y = Чото 5
      return (x + y)
   }

let second =
   чокак ,
     let! x = Ничо
     let! y = Чото 5
     return x+y
   }
Syntactic sugar
Sweeties

•   Partial application
•   Pipelining
•   Composition
•   List comprehension
•   Operators overriding
•   AST modifications
•   Measurement units
Million years ago there wasn’t LINQ
 And I still program C# 2. Can I have some DSL?
AdHoc LINQ
Calculation<Item> calculation =
         Time.Between(
            Select.First(thisYear),
            Select.Last(thisYear)
         );
Simples DSLs on .NET

SAMPLES
Validation DSL : IronPython




discussion    demo       discussion
Validation DSL : IronPython

public class User : ValidationBase
{
   [Validation("first_name_length")]
   public string FirstName { get; set; }
}
Validation DSL : IronPython

<rule name="last_name_length"
 message="Last name must be at least 2
 characters">
  <![CDATA[result = property_value != None
 and len(property_value) >= 2]]>
</rule>
Validation DSL : IronPython




PythonEngine::Execute(“python code here”)
Validation DSL : Boo


             Rules
             (Boo)


     Model
      (C#)
                 ASP.NET
                  MVC
                Application
Validation DSL : Boo

public class User
{
  public string Username { get; set; }
  public string Password { get; set; }
}
Validation DSL : Boo

rule_for "User":
  validate def(x):
      results = create_results()
      if string.IsNullOrEmpty(x.Username)
             return results
Validation DSL : Boo

Boo.Lang.Interpreter. InteractiveInterpreter
  _interpreter;
Func<List<ValidationResult>> createResults = (()
  => new List<ValidationResult>());
_interpreter.SetValue("create_results",
  createResults);
Validation DSL : Boo
Boo:
results.Add(fail("Username and Password are required"))
C#:
CompilerContext ctx =
  _interpreter.EvalCompilerInput(new
  FileInput(_filePath));
foreach (CompilerError error in ctx.Errors)
       {
             sb.AppendLine(error.Message);
       }
Object2RSS DSL : Boo


             Rules
             (Boo)


     Model
      (C#)
                 ASP.NET
                  MVC
                Application
Object2RSS DSL : Boo
public class Product
   {
          public int Id { get; set; }

          public string Name { get; set; }

          public string Description { get; set; }

          public double Price { get; set; }

          public DateTime CreateDate { get; set; }

          public Manufacturer Manufacturer { get; set; }
   }
Object2RSS DSL : Boo
rule_for "Product":
   title def(x):
        return "${x.Manufacturer.Name.ToUpper()} -
   ${x.Name}"
   description def(x):
        return x.Description
   link def(x):
        return "http://codevoyeur.com/products/${x.Id}"
   pubDate def(x):
        return x.CreateDate.ToString("s")
Object2RSS DSL : Boo
var engine = new RssDslEngine();
foreach (T item in items)
  {
      writer.WriteStartElement("item");
      List<string> fields = RssFieldFactory.Create();
      fields.ForEach(x =>
  writer.WriteElementString(x,
      engine.Execute(item, x)));
      writer.WriteEndElement();
  }
Object2RSS DSL : Boo
public string Execute(object o, string field)
     {
              string ruleName = o.GetType().Name;
              if (_rules.ContainsKey(ruleName))
              {
                       return _rules[ruleName][field].Invoke(o);
              }
              else
              {
                       throw new ApplicationException("Invalid rule
name");
              }
     }
A BDD framework for .NET and Mono

SPECTER FRAMEWORK
MiniBar specification tutorial
MiniBar specification tutorial
import Specter.Framework
import Bender
context "At Bender's bar":
   _bar as duck
   setup:
          subject _bar = Bender.MiniBar()
   specify { _bar.DrinkOneBeer() }.Must.Not.Throw()
   specify "If I drink 5 beers then I owe 5 bucks":
          for i in range(5):
                      _bar.DrinkOneBeer()
          _bar.Balance.Must.Equal(-5)
   specify "If I drink more than ten beers then I get drunk":
          for i in range(10):
                      _bar.DrinkOneBeer()
          { _bar.DrinkOneBeer() }.Must.Throw()
MiniBar specification tutorial
import Specter.Framework
import Bender
context "At Bender's bar":
   _bar as duck
   setup:                                [NUnit.Framework.TestFixture]
          subject _bar = Bender.MiniBar()class EmptyStack:
   specify { _bar.DrinkOneBeer() }.Must.Not.Throw()
   specify "If I drink 5 beers then I owe 5 bucks":
          for i in range(5):
                      _bar.DrinkOneBeer()
          _bar.Balance.Must.Equal(-5)
   specify "If I drink more than ten beers then I get drunk":
          for i in range(10):
                      _bar.DrinkOneBeer()
          { _bar.DrinkOneBeer() }.Must.Throw()
MiniBar specification tutorial
import Specter.Framework                       [NUnit.Framework.SetUp]
import Bender                                  def SetUp():
context "At Bender's bar":
   _bar as duck                                           subject _bar =
   setup:
          subject _bar = Bender.MiniBar()                 Bender.MiniBar()
   specify { _bar.DrinkOneBeer() }.Must.Not.Throw()
   specify "If I drink 5 beers then I owe 5 bucks":
          for i in range(5):
                      _bar.DrinkOneBeer()
          _bar.Balance.Must.Equal(-5)
   specify "If I drink more than ten beers then I get drunk":
          for i in range(10):
                      _bar.DrinkOneBeer()
          { _bar.DrinkOneBeer() }.Must.Throw()
MiniBar specification tutorial
import Specter.Framework
import Bender
context "At Bender's bar":
   _bar as duck
   setup:
          subject _bar = Bender.MiniBar()
   specify { _bar.DrinkOneBeer() }.Must.Not.Throw()
   specify "If I drink 5 beers then I owe 5 bucks":
          for i in range(5):
                      _bar.DrinkOneBeer()
          _bar.Balance.Must.Equal(-5)
  [NUnit.Framework.Test] then I get drunk":
   specify "If I drink more than ten beers
          for i in range(10):
  def BarDrinkOneBeerMustNotThrow():
                      _bar.DrinkOneBeer()
               Assert.DoesNotThrow(_bar. DrinkOneBeer())
          { _bar.DrinkOneBeer() }.Must.Throw()
MiniBar specification tutorial
                  [NUnit.Framework.Test]
import Specter.Framework
import Bender         def IfIDrink5BeersThenIOwe5Bucks():
context "At Bender's bar":        for i in range(5):
   _bar as duck                               _bar.DrinkOneBeer()
   setup:                         Int32MustModule.Must(_bar.Balance, “Bar
          subject _bar = Bender.MiniBar() -5").Equal(-5)
                      balance must equal
   specify { _bar.DrinkOneBeer() }.Must.Not.Throw()
   specify "If I drink 5 beers then I owe 5 bucks":
          for i in range(5):
                      _bar.DrinkOneBeer()
          _bar.Balance.Must.Equal(-5)
   specify "If I drink more than ten beers then I get drunk":
          for i in range(10):
                      _bar.DrinkOneBeer()
          { _bar.DrinkOneBeer() }.Must.Throw()
MiniBar specification tutorial
       [NUnit.Framework.Test]
import Specter.Framework
import Bender
contextdef IfiDrinkMoreThanTenBeersThenIGetDrunk():
        "At Bender's bar":
   _bar as duck
   setup:
                   for i in range(10):
                                       _bar.DrinkOneBeer()
          subject _bar = Bender.MiniBar()
   specify { _bar.DrinkOneBeer() }.Must.Not.Throw()
                   Assert.Throws((typeof(InvalidOperationExc
   specify "If I drink 5 beers then I owe 5 bucks":
       eption), _bar.DrinkOneBeer())
          for i in range(5):
                      _bar.DrinkOneBeer()
          _bar.Balance.Must.Equal(-5)
   specify "If I drink more than ten beers then I get drunk":
          for i in range(10):
                      _bar.DrinkOneBeer()
          { _bar.DrinkOneBeer() }.Must.Throw()
MiniBar specification tutorial
MiniBar specification tutorial

namespace Bender
  class MiniBar:
      def DrinkOneBeer():
            pass
      [getter(“Balance”)+
      _balance = 0
MiniBar specification tutorial
MiniBar specification tutorial
namespace Bender
  class MiniBar:
      def DrinkOneBeer():
            _balance--
            if _balance < -10:
                   raise System.Exception("i'm
  drunk")
      [getter(“Balance”)+
      _balance = 0
MiniBar specification tutorial
thx.
Need more?
• http://www.microsoft.com/soa/products/oslo.aspx
• http://www.jetbrains.com/mps/index.html
• http://blogs.msdn.com/wesdyer/archive/2008/01/11/the-
  marvels-of-monads.aspx
• http://www.google.com/
Resources

• http://www.code-
  magazine.com/article.aspx?quickid=0902041
  &page=1 (Building Domain Specific
  Languages in C#)
• http://bradfordcross.blogspot.com/2009/01/e
  xternal-dsl-vs-internal-dsl-smack-
  down_24.html (External DSL vs. Internal DSL
  Smack Down)
Resources

• http://www.paulgraham.com/
• http://martinfowler.com/
• http://en.wikipedia.org/wiki/Domain-
  specific_programming_language
• http://msdn.microsoft.com/en-
  us/library/bb126235.aspx

Contenu connexe

Tendances

Write Your Own JVM Compiler
Write Your Own JVM CompilerWrite Your Own JVM Compiler
Write Your Own JVM Compiler
Erin Dees
 
Boogie 2011 Hi-Lite
Boogie 2011 Hi-LiteBoogie 2011 Hi-Lite
Boogie 2011 Hi-Lite
AdaCore
 
GDG DART Event at Karachi
GDG DART Event at KarachiGDG DART Event at Karachi
GDG DART Event at Karachi
Imam Raza
 

Tendances (20)

Sugar Presentation - YULHackers March 2009
Sugar Presentation - YULHackers March 2009Sugar Presentation - YULHackers March 2009
Sugar Presentation - YULHackers March 2009
 
Your Own Metric System
Your Own Metric SystemYour Own Metric System
Your Own Metric System
 
Quick Intro To JRuby
Quick Intro To JRubyQuick Intro To JRuby
Quick Intro To JRuby
 
Write Your Own JVM Compiler
Write Your Own JVM CompilerWrite Your Own JVM Compiler
Write Your Own JVM Compiler
 
Writing Parsers and Compilers with PLY
Writing Parsers and Compilers with PLYWriting Parsers and Compilers with PLY
Writing Parsers and Compilers with PLY
 
1 hour dive into Erlang/OTP
1 hour dive into Erlang/OTP1 hour dive into Erlang/OTP
1 hour dive into Erlang/OTP
 
Thnad's Revenge
Thnad's RevengeThnad's Revenge
Thnad's Revenge
 
Creating Domain Specific Languages in Python
Creating Domain Specific Languages in PythonCreating Domain Specific Languages in Python
Creating Domain Specific Languages in Python
 
Start dart
Start dartStart dart
Start dart
 
CS4200 2019 | Lecture 3 | Parsing
CS4200 2019 | Lecture 3 | ParsingCS4200 2019 | Lecture 3 | Parsing
CS4200 2019 | Lecture 3 | Parsing
 
Boogie 2011 Hi-Lite
Boogie 2011 Hi-LiteBoogie 2011 Hi-Lite
Boogie 2011 Hi-Lite
 
Playfulness at Work
Playfulness at WorkPlayfulness at Work
Playfulness at Work
 
Patterns for JVM languages JokerConf
Patterns for JVM languages JokerConfPatterns for JVM languages JokerConf
Patterns for JVM languages JokerConf
 
Meta Object Protocols
Meta Object ProtocolsMeta Object Protocols
Meta Object Protocols
 
Parm
ParmParm
Parm
 
GDG DART Event at Karachi
GDG DART Event at KarachiGDG DART Event at Karachi
GDG DART Event at Karachi
 
Programming languages
Programming languagesProgramming languages
Programming languages
 
Introduction To Groovy 2005
Introduction To Groovy 2005Introduction To Groovy 2005
Introduction To Groovy 2005
 
CocoaConf: The Language of Mobile Software is APIs
CocoaConf: The Language of Mobile Software is APIsCocoaConf: The Language of Mobile Software is APIs
CocoaConf: The Language of Mobile Software is APIs
 
Groovy presentation
Groovy presentationGroovy presentation
Groovy presentation
 

En vedette

Backpacks to briefcases, spring 2014
Backpacks to briefcases, spring 2014Backpacks to briefcases, spring 2014
Backpacks to briefcases, spring 2014
Laura Ledgerwood
 
Современный веб-сайт на Share point
Современный веб-сайт на Share pointСовременный веб-сайт на Share point
Современный веб-сайт на Share point
Vitaly Baum
 
SharePoint: Object Model & Web Parts
SharePoint: Object Model & Web PartsSharePoint: Object Model & Web Parts
SharePoint: Object Model & Web Parts
Vitaly Baum
 
Using Social Media To Job Search
Using Social Media To Job SearchUsing Social Media To Job Search
Using Social Media To Job Search
Laura Ledgerwood
 
Developing .net without leaving from unix shell
Developing .net without leaving from unix shellDeveloping .net without leaving from unix shell
Developing .net without leaving from unix shell
Vitaly Baum
 
Remoto powered by Windows Azure
Remoto powered by Windows AzureRemoto powered by Windows Azure
Remoto powered by Windows Azure
Vitaly Baum
 

En vedette (18)

Backpacks to briefcases, spring 2014
Backpacks to briefcases, spring 2014Backpacks to briefcases, spring 2014
Backpacks to briefcases, spring 2014
 
Unobtrusive JavaScript
Unobtrusive JavaScriptUnobtrusive JavaScript
Unobtrusive JavaScript
 
Современный веб-сайт на Share point
Современный веб-сайт на Share pointСовременный веб-сайт на Share point
Современный веб-сайт на Share point
 
Moscow ALT.NET Intro
Moscow ALT.NET IntroMoscow ALT.NET Intro
Moscow ALT.NET Intro
 
SharePoint: Object Model & Web Parts
SharePoint: Object Model & Web PartsSharePoint: Object Model & Web Parts
SharePoint: Object Model & Web Parts
 
Using Social Media To Job Search
Using Social Media To Job SearchUsing Social Media To Job Search
Using Social Media To Job Search
 
SharePoint, LINQ, OData
SharePoint, LINQ, ODataSharePoint, LINQ, OData
SharePoint, LINQ, OData
 
Решения сообщества для SharePoint
Решения сообщества для SharePointРешения сообщества для SharePoint
Решения сообщества для SharePoint
 
SharePoint Search от мала до велика
SharePoint Search от мала до великаSharePoint Search от мала до велика
SharePoint Search от мала до велика
 
Twitter Job Search
Twitter Job SearchTwitter Job Search
Twitter Job Search
 
SharePoint Introduction
SharePoint IntroductionSharePoint Introduction
SharePoint Introduction
 
DLR Hosting
DLR HostingDLR Hosting
DLR Hosting
 
SharePoint и внешние данные
SharePoint и внешние данныеSharePoint и внешние данные
SharePoint и внешние данные
 
Azure Mobile Backend
Azure Mobile BackendAzure Mobile Backend
Azure Mobile Backend
 
ASP.NET MVC Internals
ASP.NET MVC InternalsASP.NET MVC Internals
ASP.NET MVC Internals
 
Sapphire
SapphireSapphire
Sapphire
 
Developing .net without leaving from unix shell
Developing .net without leaving from unix shellDeveloping .net without leaving from unix shell
Developing .net without leaving from unix shell
 
Remoto powered by Windows Azure
Remoto powered by Windows AzureRemoto powered by Windows Azure
Remoto powered by Windows Azure
 

Similaire à Building DSLs On CLR and DLR (Microsoft.NET)

Smoothing Your Java with DSLs
Smoothing Your Java with DSLsSmoothing Your Java with DSLs
Smoothing Your Java with DSLs
intelliyole
 
Domain-Specific Languages for Composable Editor Plugins (LDTA 2009)
Domain-Specific Languages for Composable Editor Plugins (LDTA 2009)Domain-Specific Languages for Composable Editor Plugins (LDTA 2009)
Domain-Specific Languages for Composable Editor Plugins (LDTA 2009)
lennartkats
 
AestasIT - Internal DSLs in Scala
AestasIT - Internal DSLs in ScalaAestasIT - Internal DSLs in Scala
AestasIT - Internal DSLs in Scala
Dmitry Buzdin
 
Linq 1224887336792847 9
Linq 1224887336792847 9Linq 1224887336792847 9
Linq 1224887336792847 9
google
 
TI1220 Lecture 14: Domain-Specific Languages
TI1220 Lecture 14: Domain-Specific LanguagesTI1220 Lecture 14: Domain-Specific Languages
TI1220 Lecture 14: Domain-Specific Languages
Eelco Visser
 
[Td 2015] what is new in visual c++ 2015 and future directions(ulzii luvsanba...
[Td 2015] what is new in visual c++ 2015 and future directions(ulzii luvsanba...[Td 2015] what is new in visual c++ 2015 and future directions(ulzii luvsanba...
[Td 2015] what is new in visual c++ 2015 and future directions(ulzii luvsanba...
Sang Don Kim
 

Similaire à Building DSLs On CLR and DLR (Microsoft.NET) (20)

NDC Sydney 2019 - Microservices for building an IDE – The innards of JetBrain...
NDC Sydney 2019 - Microservices for building an IDE – The innards of JetBrain...NDC Sydney 2019 - Microservices for building an IDE – The innards of JetBrain...
NDC Sydney 2019 - Microservices for building an IDE – The innards of JetBrain...
 
Smoothing Your Java with DSLs
Smoothing Your Java with DSLsSmoothing Your Java with DSLs
Smoothing Your Java with DSLs
 
Domain-Specific Languages for Composable Editor Plugins (LDTA 2009)
Domain-Specific Languages for Composable Editor Plugins (LDTA 2009)Domain-Specific Languages for Composable Editor Plugins (LDTA 2009)
Domain-Specific Languages for Composable Editor Plugins (LDTA 2009)
 
AestasIT - Internal DSLs in Scala
AestasIT - Internal DSLs in ScalaAestasIT - Internal DSLs in Scala
AestasIT - Internal DSLs in Scala
 
PIL - A Platform Independent Language
PIL - A Platform Independent LanguagePIL - A Platform Independent Language
PIL - A Platform Independent Language
 
Practical Groovy DSL
Practical Groovy DSLPractical Groovy DSL
Practical Groovy DSL
 
Linq 1224887336792847 9
Linq 1224887336792847 9Linq 1224887336792847 9
Linq 1224887336792847 9
 
Iron Languages - NYC CodeCamp 2/19/2011
Iron Languages - NYC CodeCamp 2/19/2011Iron Languages - NYC CodeCamp 2/19/2011
Iron Languages - NYC CodeCamp 2/19/2011
 
Big Data Day LA 2015 - Compiling DSLs for Diverse Execution Environments by Z...
Big Data Day LA 2015 - Compiling DSLs for Diverse Execution Environments by Z...Big Data Day LA 2015 - Compiling DSLs for Diverse Execution Environments by Z...
Big Data Day LA 2015 - Compiling DSLs for Diverse Execution Environments by Z...
 
TI1220 Lecture 14: Domain-Specific Languages
TI1220 Lecture 14: Domain-Specific LanguagesTI1220 Lecture 14: Domain-Specific Languages
TI1220 Lecture 14: Domain-Specific Languages
 
Creating Domain Specific Languages in F#
Creating Domain Specific Languages in F#Creating Domain Specific Languages in F#
Creating Domain Specific Languages in F#
 
[Td 2015] what is new in visual c++ 2015 and future directions(ulzii luvsanba...
[Td 2015] what is new in visual c++ 2015 and future directions(ulzii luvsanba...[Td 2015] what is new in visual c++ 2015 and future directions(ulzii luvsanba...
[Td 2015] what is new in visual c++ 2015 and future directions(ulzii luvsanba...
 
Tml for Objective C
Tml for Objective CTml for Objective C
Tml for Objective C
 
ConFoo Montreal - Microservices for building an IDE - The innards of JetBrain...
ConFoo Montreal - Microservices for building an IDE - The innards of JetBrain...ConFoo Montreal - Microservices for building an IDE - The innards of JetBrain...
ConFoo Montreal - Microservices for building an IDE - The innards of JetBrain...
 
CS 354 Programmable Shading
CS 354 Programmable ShadingCS 354 Programmable Shading
CS 354 Programmable Shading
 
Tips And Tricks For Bioinformatics Software Engineering
Tips And Tricks For Bioinformatics Software EngineeringTips And Tricks For Bioinformatics Software Engineering
Tips And Tricks For Bioinformatics Software Engineering
 
Ruby DSL
Ruby DSLRuby DSL
Ruby DSL
 
C Language
C LanguageC Language
C Language
 
Architecting Domain-Specific Languages
Architecting Domain-Specific LanguagesArchitecting Domain-Specific Languages
Architecting Domain-Specific Languages
 
Microservices for building an IDE – The innards of JetBrains Rider - TechDays...
Microservices for building an IDE – The innards of JetBrains Rider - TechDays...Microservices for building an IDE – The innards of JetBrains Rider - TechDays...
Microservices for building an IDE – The innards of JetBrains Rider - TechDays...
 

Building DSLs On CLR and DLR (Microsoft.NET)

  • 1. Building DSL s on the CLR and DLR
  • 2. VitalyBaum vbaum@live.com butaji MaximMoiseev maxim.moiseev@gmail.com moiseev
  • 4. The short annotation DOMAIN SPECIFIC LANGUAGES
  • 5. Domain Specific Languages (DSLs) are limited forms of computer language designed for a specific class of problems.
  • 6. Martin Fowler “(DSL) is a computer language that's targeted to a particular kind of problem, rather than a general purpose language that's aimed at any kind of software problem.”
  • 7. Paul Graham “*Lisp Programmers+ follow a principle which could be called bottom-up design-- changing the language to suit the problem.”
  • 9. Types of DSL Internal External • Written in host • Separate to host language language • Conventional use of • Needs the subset of host language compiler/interpreter to syntax execute
  • 10. Types of DSL Internal External • Tied to base language • Lack of Symbolic • Awkward with Integration mainstream • Complex parser/generator technologies • Ignorant IDEs • (language cacophony)
  • 11. Types of DSL Internal External • LINQ (C#) • Regexp • Monads (Haskell) • SQL • Workflows (F#) • CSS • Sequence expressions • Ant (F#) • XSLT • List comprehensions (Haskell, Python)
  • 12. Types of DSL Graphical DSL Log Workflow Activity Clear Activity Shutdown Activity
  • 13. DSL Oriented .NET Languages LANGUAGES
  • 14. F# Ruby Lisp Python Boo C# Smalltalk
  • 15. F# Ruby Lisp Python CLR Boo DLR C# Smalltalk
  • 16. I <3
  • 17. The important advantages over a GPL WHY SHOULD WE USE DSL?
  • 18. Why should we use DSL • Domain-specific abstractions: a DSL provides pre- defined abstractions to directly represent concepts from the application domain. Consequently, domain experts themselves can understand, validate, modify, and often even develop DSL program • Domain-specific concrete syntax: a DSL offers a natural notation for a given domain and avoids syntactic clutter that often results when using a GPL.
  • 19. Why should we use DSL • Domain-specific error checking: a DSL enables building static analyzers that can find more errors than similar analyzers for a GPL and that can report the errors in language familiar to the domain expert. • Domain-specific optimizations: a DSL creates opportunities for generating optimized code base on domain-specific knowledge, which is usually not available to a compiler for a GPL.
  • 20. Why should we use DSL • Domain-specific tool support: a DSL creates opportunities to improve any tooling aspect of a development environment, including, editors, debuggers, version control, etc.; the domain-specific knowledge that is explicitly captured by a DSL can be used to provide more intelligent tool support for developers.
  • 21. Why is DSL good? Business Peoples and “Rules” Developers and their “Magic”
  • 22. Read and Write director of finance for the client bank to edit, test, and deploy the business rules of the system without any assistance from IT
  • 23. Read Write
  • 25. Better code readability • Fluent interfaces • Extension methods • LINQ • Workflows • Syntactic sugar • AdHoc LINQ
  • 26. Fluent interfaces Expect .Once .On(…) .Method(…) .WithAnyArguments() .Will( Return.Value(…) ) NMock mocking library usage
  • 27. Fluent interfaces Expect public static Expect {…} .Once IRecieverSyntax .On(…) IMethodSyntax .Method(…) IArgumentSyntax .WithAnyArguments() IActionSyntax .Will( Return.Value(…) IAction )
  • 28. Fluent interfaces public class ExpectationBuilder: IReceiverSyntax, IMethodSyntax, IArgumentSyntax, IActionSyntax {…} public IMethodSyntax On(…){ // … return this; } public IArgumentSyntax Method(…){ // … return this; }
  • 30. Timespan Literals print(50s) // 50 seconds print(1d) // 1 day print(2m) // 2 minutes print(42ms) // 42 miliseconds print("Tomorrow this time will be: ${date.Now + 1d}")
  • 31. String interpolation print("Now is ${date.Now}.") print("Tomorrow will be ${date.Now + 1d}")
  • 32. Extension methods DateTime now = VS DateTime res = DateTime.Now; 3.Days() TimeSpan span = .From( TimeSpan.FromDays(3); DateTime.Now DateTime res = ) now + span;
  • 33. Extension methods public static class MyExtensions { public static TimeSpan Days(this int i) { return TimeSpan.FromDays(i); } public static DateTime From( this TimeSpan span, DateTime dt) { return dt + span; } }
  • 34. Man, there’s LINQ already Can’t we use that?
  • 35. We do
  • 36. LINQ string s1 = GetS1(); VS var res = string s2 = GetS2(); from a in GetS1() string res = from b in GetS2() string.Empty; select a + b; if(s1 != null && s2 != null){ res = s1 + s2; }
  • 37. LINQ public class Maybe<T> { public T Value { get; private set; } public bool HasValue { get; private set; } private Maybe() { HasValue = false; } public Maybe(T value) { Value = value; HasValue = true; } public static readonly Maybe<T> Nothing = new Maybe<T>(); }
  • 38. LINQ public static Maybe<T> ToMaybe<T>(this T value) { return new Maybe<T>(value); } public static Maybe<U> SelectMany<T, U>( this Maybe<T> src, Func<T, Maybe<U>> f) { if (!src.HasValue) { return Maybe<U>.Nothing; } return f(src.Value); }
  • 39. Important • LINQ is a Monad • F# Workflows are monads • What isn’t?! "[W]hen the designers of F# talked with the designers of Haskell about this, they agreed that the word monad is a bit obscure and sounds a little daunting and that using other names might be wise.“ [F# Workflows and Haskell Monads, Expert F#, p232]
  • 40. C# is no fun. Want more!
  • 42. Workflows type Чо<'a> = | Ничо | Чото of 'a let bindMaybe x f = match x with | Ничо -> Ничо | Чото y -> f y type MaybeBuilder() = member x.Return(what) = Чото what member x.Bind(m, f) = bindMaybe m f let чокак = new MaybeBuilder()
  • 43. Workflows let first = чокак , let! x = Чото 6 let! y = Чото 5 return (x + y) } let second = чокак , let! x = Ничо let! y = Чото 5 return x+y }
  • 45. Sweeties • Partial application • Pipelining • Composition • List comprehension • Operators overriding • AST modifications • Measurement units
  • 46. Million years ago there wasn’t LINQ And I still program C# 2. Can I have some DSL?
  • 47. AdHoc LINQ Calculation<Item> calculation = Time.Between( Select.First(thisYear), Select.Last(thisYear) );
  • 48. Simples DSLs on .NET SAMPLES
  • 49.
  • 50. Validation DSL : IronPython discussion demo discussion
  • 51. Validation DSL : IronPython public class User : ValidationBase { [Validation("first_name_length")] public string FirstName { get; set; } }
  • 52. Validation DSL : IronPython <rule name="last_name_length" message="Last name must be at least 2 characters"> <![CDATA[result = property_value != None and len(property_value) >= 2]]> </rule>
  • 53. Validation DSL : IronPython PythonEngine::Execute(“python code here”)
  • 54.
  • 55. Validation DSL : Boo Rules (Boo) Model (C#) ASP.NET MVC Application
  • 56. Validation DSL : Boo public class User { public string Username { get; set; } public string Password { get; set; } }
  • 57. Validation DSL : Boo rule_for "User": validate def(x): results = create_results() if string.IsNullOrEmpty(x.Username) return results
  • 58. Validation DSL : Boo Boo.Lang.Interpreter. InteractiveInterpreter _interpreter; Func<List<ValidationResult>> createResults = (() => new List<ValidationResult>()); _interpreter.SetValue("create_results", createResults);
  • 59. Validation DSL : Boo Boo: results.Add(fail("Username and Password are required")) C#: CompilerContext ctx = _interpreter.EvalCompilerInput(new FileInput(_filePath)); foreach (CompilerError error in ctx.Errors) { sb.AppendLine(error.Message); }
  • 60. Object2RSS DSL : Boo Rules (Boo) Model (C#) ASP.NET MVC Application
  • 61. Object2RSS DSL : Boo public class Product { public int Id { get; set; } public string Name { get; set; } public string Description { get; set; } public double Price { get; set; } public DateTime CreateDate { get; set; } public Manufacturer Manufacturer { get; set; } }
  • 62. Object2RSS DSL : Boo rule_for "Product": title def(x): return "${x.Manufacturer.Name.ToUpper()} - ${x.Name}" description def(x): return x.Description link def(x): return "http://codevoyeur.com/products/${x.Id}" pubDate def(x): return x.CreateDate.ToString("s")
  • 63. Object2RSS DSL : Boo var engine = new RssDslEngine(); foreach (T item in items) { writer.WriteStartElement("item"); List<string> fields = RssFieldFactory.Create(); fields.ForEach(x => writer.WriteElementString(x, engine.Execute(item, x))); writer.WriteEndElement(); }
  • 64. Object2RSS DSL : Boo public string Execute(object o, string field) { string ruleName = o.GetType().Name; if (_rules.ContainsKey(ruleName)) { return _rules[ruleName][field].Invoke(o); } else { throw new ApplicationException("Invalid rule name"); } }
  • 65. A BDD framework for .NET and Mono SPECTER FRAMEWORK
  • 67. MiniBar specification tutorial import Specter.Framework import Bender context "At Bender's bar": _bar as duck setup: subject _bar = Bender.MiniBar() specify { _bar.DrinkOneBeer() }.Must.Not.Throw() specify "If I drink 5 beers then I owe 5 bucks": for i in range(5): _bar.DrinkOneBeer() _bar.Balance.Must.Equal(-5) specify "If I drink more than ten beers then I get drunk": for i in range(10): _bar.DrinkOneBeer() { _bar.DrinkOneBeer() }.Must.Throw()
  • 68. MiniBar specification tutorial import Specter.Framework import Bender context "At Bender's bar": _bar as duck setup: [NUnit.Framework.TestFixture] subject _bar = Bender.MiniBar()class EmptyStack: specify { _bar.DrinkOneBeer() }.Must.Not.Throw() specify "If I drink 5 beers then I owe 5 bucks": for i in range(5): _bar.DrinkOneBeer() _bar.Balance.Must.Equal(-5) specify "If I drink more than ten beers then I get drunk": for i in range(10): _bar.DrinkOneBeer() { _bar.DrinkOneBeer() }.Must.Throw()
  • 69. MiniBar specification tutorial import Specter.Framework [NUnit.Framework.SetUp] import Bender def SetUp(): context "At Bender's bar": _bar as duck subject _bar = setup: subject _bar = Bender.MiniBar() Bender.MiniBar() specify { _bar.DrinkOneBeer() }.Must.Not.Throw() specify "If I drink 5 beers then I owe 5 bucks": for i in range(5): _bar.DrinkOneBeer() _bar.Balance.Must.Equal(-5) specify "If I drink more than ten beers then I get drunk": for i in range(10): _bar.DrinkOneBeer() { _bar.DrinkOneBeer() }.Must.Throw()
  • 70. MiniBar specification tutorial import Specter.Framework import Bender context "At Bender's bar": _bar as duck setup: subject _bar = Bender.MiniBar() specify { _bar.DrinkOneBeer() }.Must.Not.Throw() specify "If I drink 5 beers then I owe 5 bucks": for i in range(5): _bar.DrinkOneBeer() _bar.Balance.Must.Equal(-5) [NUnit.Framework.Test] then I get drunk": specify "If I drink more than ten beers for i in range(10): def BarDrinkOneBeerMustNotThrow(): _bar.DrinkOneBeer() Assert.DoesNotThrow(_bar. DrinkOneBeer()) { _bar.DrinkOneBeer() }.Must.Throw()
  • 71. MiniBar specification tutorial [NUnit.Framework.Test] import Specter.Framework import Bender def IfIDrink5BeersThenIOwe5Bucks(): context "At Bender's bar": for i in range(5): _bar as duck _bar.DrinkOneBeer() setup: Int32MustModule.Must(_bar.Balance, “Bar subject _bar = Bender.MiniBar() -5").Equal(-5) balance must equal specify { _bar.DrinkOneBeer() }.Must.Not.Throw() specify "If I drink 5 beers then I owe 5 bucks": for i in range(5): _bar.DrinkOneBeer() _bar.Balance.Must.Equal(-5) specify "If I drink more than ten beers then I get drunk": for i in range(10): _bar.DrinkOneBeer() { _bar.DrinkOneBeer() }.Must.Throw()
  • 72. MiniBar specification tutorial [NUnit.Framework.Test] import Specter.Framework import Bender contextdef IfiDrinkMoreThanTenBeersThenIGetDrunk(): "At Bender's bar": _bar as duck setup: for i in range(10): _bar.DrinkOneBeer() subject _bar = Bender.MiniBar() specify { _bar.DrinkOneBeer() }.Must.Not.Throw() Assert.Throws((typeof(InvalidOperationExc specify "If I drink 5 beers then I owe 5 bucks": eption), _bar.DrinkOneBeer()) for i in range(5): _bar.DrinkOneBeer() _bar.Balance.Must.Equal(-5) specify "If I drink more than ten beers then I get drunk": for i in range(10): _bar.DrinkOneBeer() { _bar.DrinkOneBeer() }.Must.Throw()
  • 74. MiniBar specification tutorial namespace Bender class MiniBar: def DrinkOneBeer(): pass [getter(“Balance”)+ _balance = 0
  • 76. MiniBar specification tutorial namespace Bender class MiniBar: def DrinkOneBeer(): _balance-- if _balance < -10: raise System.Exception("i'm drunk") [getter(“Balance”)+ _balance = 0
  • 78. thx.
  • 79. Need more? • http://www.microsoft.com/soa/products/oslo.aspx • http://www.jetbrains.com/mps/index.html • http://blogs.msdn.com/wesdyer/archive/2008/01/11/the- marvels-of-monads.aspx • http://www.google.com/
  • 80. Resources • http://www.code- magazine.com/article.aspx?quickid=0902041 &page=1 (Building Domain Specific Languages in C#) • http://bradfordcross.blogspot.com/2009/01/e xternal-dsl-vs-internal-dsl-smack- down_24.html (External DSL vs. Internal DSL Smack Down)
  • 81. Resources • http://www.paulgraham.com/ • http://martinfowler.com/ • http://en.wikipedia.org/wiki/Domain- specific_programming_language • http://msdn.microsoft.com/en- us/library/bb126235.aspx