Jeg kan huske, at jeg for en del år siden hørte Don Box til afslutningssessionen ved TechEd i Barcelona fortælle om, at noget nær den største sikkerhedsrisiko i .NET var, at alle klasser pr. default ikke er “sealed”.  Jeg ved ikke, om det er en kæmpe sikkerhedsrisiko, men manden havde vel fat i noget (som han som regel har).  Nedarvning er ikke svaret på alles problemer, så det burde vel egentlig være sådan, at man aktivt skal åbne for nedarvning af ens klasse i stedet for som nu, hvor man aktivt skal lukke for det.

Men også ganske små detaljer kan give bugs, hvis man ikke tager højde for potentiel nedarvning.

Jeg stødte selv ind i en lille bug forleden, fordi jeg i min naivitet valgte at nedarve fra en klasse, der ikke var designet til nedarvning.  Der opstod heldigvis ikke noget stort brud på sikkerheden i virksomheden af den grund – i stedet fik jeg bare en almindelig null-reference exception.

Klassen, jeg nedarvede fra, indeholdt bl.a. følgende linjer:

   1:  Assembly assem = this.GetType().Assembly;
   2:  var resourceStream = assem.GetManifestResourceStream(this.GetType(), "ResourceName");

Problemet er kaldene til this.GetType().  Hvis klassen er nedarvet, vil GetType() returnere typen for den nedarvede klasse, og hvis de to klasser ikke ligger i samme assembly, vil .NET kigge i det forkerte assembly efter den angivne resource.  Så lektien må være, at man skal tænke sig nøje om for ikke at putte sealed på sin klasse.

Her i sommervarmen var det måske på tide at lege lidt med lambda udtryk: 

Expression<Func<double,double>> f = x => x + 1;

Hvis vi ser på lambda udtryk med matematiske briller vil vi ofte gerne differentiere udtrykket for f.eks. at finde maksimum eller nulpunkter. Differentialregning er heldigvis noget med en masse regler og så hårdt arbejde for resten - hvilket jo er computerens speciale. Men hvor nemt er det egentligt at differentiere et lambda udtryk?

Ovenstående udtryk parses til en Expression-træstruktur, som er et standard abstrakt syntaks træ. De enkelte noder i træer repræsenterer operatorer (plus, minus, gange og dividere, men også større end og mindre end), tal (konstanter) og symboler (også kaldet parametre som x ovenfor). Der er en helt række af expression typer (se ExpressionType for komplet liste), men noget kortere liste at klasser som nedarver Expression.

Mange ExpressionType værdier bruger f.eks. BinaryExpression - det gælder bl.a. Add, Subtract, Multiply og Divide, men også diverse boolske operatorer som f.eks. LessThan og GreaterThan (bemærk dog at disse returner bool og ikke double).

Expression finder du i System.Linq.Expression men benyttes også af Dynamic Language Runtime (DLR). Det er specielt udtryk til at styre flow i et program og tildeling af værdier som benyttes af DLR, men det vil vi ignorere i et matematisk setup.

Vi vælger at implementere Derive som en extension metode:

public static Expression Derive(this Expression e, string parameterName)
{
  switch (e.NodeType)
  {
    case ExpressionType.Add:
      ...
      break;
    
    ...
  }
}

Vi skal naturligvis implementere regler for alle værdier ExpressionType som giver matematisk mening, men først lige en metode mere.

public static Expression Derive(this Expression e, string parameterName)
{
  return Expression.Lambda(e.Body.Derive(parameterName), e.Parameters);
}

Denne metode sikrer at vi kan benytte Derive på LambdaExpression og at resultat også bliver en LambdaExpression. Vi har altså vores afledte giver som:

Expression> df = f.Derive("x");

I vores eksempel indgår tre node typer: Parameter, Constant og Add

case ExpressionType.Parameter:
  {
    ParameterExpression pe = (ParameterExpression)e;
    return Expression.Constant(pe.Name == parametername ? 1.0 : 0.0)
  }
  
case ExpressionType.Constant:
  return Expression.Constant(0.0);
  
case ExpressionType.Add:
  {
    BinaryExpressiob be = (BinaryExpression)e;
    return Expression.Add(
      be.Left.Derive(parameterName),
      be.Right.Derive(parameterName)
    );
  }

Hvilket giver os

df = x => 1 + 0;

Bemærk, at vi arbejder med doubles hele vejen igennem, ellers fejler programmet runtime ved at der ikke findes en add-operator som tager int som det ene argument og double som det andet. Resultat fra vores Derive metode er korrekt, men ikke specielt pænt at se på og måske heller ikke optimalt rent beregningsmæssigt. Til det formål foreslår jeg endnu en ekstension metode:

public static Expression Simplify(this Expression e)
{
  ...
}

Men den øvelse gemmer vi til en anden god gang - der er endnu meget arbejde på Derive.

En anden ting man bør bemærke er at der oprettes nye Expression når man skal redigere et udtryk. Det er et underliggende princip at Expression instanserne ikke kan ændres (de er immutable), hvilket man udnytter til Multiply operatoren i Derive:

case ExpressionType.Multiply: // (fg)'=f'g+fg'
  {
    BinaryExpression be = (BinaryExpression)e;
    Expression dleft = be.Left.Derive(parameterName);
    Expression dright = be.Right.Derive(parameterName);
    return Expression.Add(
      Expression.Multiply(dleft, be.Right),
      Expression.Multiply(be.Left, dright)
    );
  }

Vi har altså genbrugt undernoderne i BinaryExpression til et nyt udtryk. Jeg vil overlade det til læseren at implementere Subtract, Divide og Negate (UnaryExpression).

For funktions kald findes typen Call og klassen MethodCallExpression som med Member (MethodInfo) giver os en reference til den funktion som skal kaldes. Det er op til os at implementere den afledte af forskellige kendte funktioner, f.eks.

(Math.Sin)':
  return Expression.Call(null, typeof(Math).GetMethod("Cos"), me.Arguments);
(Math.Cos)':
  return Expression.Negate(Expression.Call(null, typeof(Math).GetMethod("Sin"),   me.Arguments);

hvor me er vores originale MethodCallExpression og me.Arguments således er de originale argumenter til funktionskaldet - jeg lader det være op til læseren at implementere kædereglen ((f(g(x)))'=f'(g(x))*g'(x)).

Endnu en stor ting fra en matematisk vinkel er at implementere potensreglen. C# har ikke nogen potens operator (^ eller ** i andre sprog), så vi skal se på ExpressionType.Call hvor metoden er Math.Pow. Den generelle potens regel er (f^g)'=f^g*(g'ln f+(g/f)*f'), men hvis g er et tal så er det den noget simplere udgave (x^n)'=n*x^(n-1):

Expression e1 = Expression.Multiply(
  me.Arguments[1], // n
  Expression.Power(
    me.Arguments[0], // x
    Expression.Subtract(me.Arguments[1], Expression.Constant(1.0)) // -1
    )
  );

dertil kommer så kædereglen:

return Expression.Multiply(e1, me.Arguments[0].Derive(parameterName));

Bemærk, at Expression.Power(...) funktionen giver os ExpressionType.Power, så hvis resultat skal differentieres igen, så skal vi også tage højde for det. Alternativt kan man benytte Expression.Call med metoden me.Method.

Det skulle være lidt til at komme igang med noget differentialregning. Heldigvis skal man "bare" følge nogle matematiske regler for at få resultatet - som måske kræver en del simplifisering for at se pænt ud, men kompileren dømmer os ikke på skønhed.