Generic type para­me­ters were intro­duced in C# 2.0, and they gave us the abil­ity to write code that works against any type that matches a set of con­straints and remove the need to cre­ate type-specific over­loads, e.g.:

image

A few years passed, and dynamic types was intro­duced in C# 4, which allows us to bypass compile-time type check­ing (type check­ing still hap­pens at run­time) when we use the dynamic key­word, e.g.:

image

this code works so long as the ‘+’ oper­a­tor is defined for the run­time types of obj1 and obj2, oth­er­wise, you’ll get a Run­time­BinderEx­cep­tion when this code is exe­cuted. This kind of type check­ing is often referred to as Duck typ­ing.

Duck typ­ing is a very pow­er­ful lan­guage fea­ture but it also makes your code less safe, as you now face the pos­si­bil­ity of hav­ing run­time type errors that would have oth­er­wise been caught by the compiler.

It’s a damn shame that there’s no way for you to com­bine the pow­ers of gener­ics and dynamic typ­ing.. because if you could, you’d be able to write DoSome­thin­gElse like this instead:

pub­lic void DoSomethingElse<T, U, V>(T obj1, U obj2) where T + U => V

{

    var obj3 = obj1 + obj2;

    Console.WriteLine(obj3);

}

which stops you from mis­tak­enly try­ing to invoke the method with an int and a List<int> at com­pile time, and saves you 10 mins of debug­ging and bug fix­ing time.

Well, would it blow your mind if I tell you that such fea­ture already exists in the .Net frame­work today? No, I kid you not, mem­ber con­straints in F# lets you do just that!

Mem­ber Constraints

In F#, you can spec­ify a sta­t­i­cally resolved type para­me­ter by pre­fix­ing it with the caret sym­bol ( ^ ), e.g. ^T. These type para­me­ters can be used with mem­ber con­straints which allows you to spec­ify that a type argu­ment must have a par­tic­u­lar mem­ber or mem­bers in order to be used.

Take the fol­low­ing F# code for instance:

image

It’s equiv­a­lent to the ear­lier C# ver­sion of DoSome­thin­gElse, but this func­tion has the fol­low­ing signature:

image

which says that the types ^a and ^b used in the func­tion must have a sta­tic mem­ber ‘+’ defined on either one of them that can be used on instances of these two types.

You can explic­itly state mem­ber con­straints too, for instance:

image

Mem­ber con­straints are very use­ful in those tight spots where you find your­self wrestling with the .Net type sys­tem, it gives you the flex­i­bil­ity of duck typ­ing but also the safety of sta­tic typ­ing, so really it gives you the best of both worlds!

Restric­tions

How­ever, use­ful as it may be, there are some restric­tions to when you can use mem­ber constraints.

First, they can­not be used with generic type para­me­ters, they can only be used with sta­t­i­cally resolved type parameters.

Sec­ondly, they can only be used with func­tions or meth­ods that are inline.

Inline func­tions

Which brings us to the topic of inline func­tions, which as the name sug­gests, cre­ates the func­tions ‘inline’.

But what does that mean? It means that, at every call site to an inlined func­tion or method, the con­crete types for the sta­t­i­cally resolved type para­me­ters (e.g. ^T, ^U) are resolved and the spe­cific code for those types are inserted at the call site.

This has the obvi­ous impli­ca­tion that the com­piler will gen­er­ate many dupli­cated IL code for inline func­tions and it increases the size of your assembly.

By con­trast, a nor­mal func­tion or method will gen­er­ate only one instance of that func­tion or method and every call site makes a ‘jump’ to the loca­tion of that func­tion or method in mem­ory to exe­cute it. The inlin­ing behav­iour also has some per­for­mance impli­ca­tions which we will go through shortly.

Restric­tions

The one major restric­tion on inline func­tions is that an inlined func­tion can­not be overloaded.

When to use inline functions

As with most pow­er­ful fea­tures, such as duck typ­ing and inline func­tions, they are often open to abuse.. Per­son­ally, I think it’s impor­tant for one to think care­fully about what it is that they’re try­ing to do before decid­ing to use the lat­est and great­est lan­guage fea­tures just for the sake of it.

Take the last code snip­pet for exam­ple, there’s no rea­son why I can’t solve this prob­lem using inter­faces and generic type para­me­ters – define an ISpeaker inter­face with a Speak mem­ber and requir­ing the para­me­ter x to be an instance of ISpeaker.

Doing so will achieve the same end goal, there will be a stronger con­tract (a well under­stood, shared inter­face) and the code will be cleaner and eas­ier to read:

image

As far as I’m aware, there are really only two main rea­sons for using inline functions:

Generic Arith­metic

This is the prob­lem inline func­tions were designed to solve, and a prob­lem that can’t be solved by using inter­faces and gener­ics because there’s no way to spe­cific con­straints on oper­a­tors with­out using mem­ber con­straints (and there­fore inline functions).

Take this sim­ple add func­tion for example:

image

with­out mak­ing it inline the para­me­ters a and b will be inferred to be of type int, and there’s no way to make this func­tion generic and usable with every numeric type (int32, int64, uint32, uint64, float, etc.). This is a prime exam­ple of when you should inline a func­tion, doing so solves the afore­men­tioned problem:

image

Per­for­mance Optimization

In some cases, it’s pos­si­ble to get a per­for­mance improve­ment by mak­ing a func­tion inline as it removes the jumps from call sites to the function’s loca­tion in memory.

Jon Har­rop gave this exam­ple of how by mak­ing the fol­low­ing fold func­tion inline it can run 5x faster:

image

image

As you can see, in my test, the inline ver­sion man­aged to run a whop­ping 8.5x faster!

This might just be too much temp­ta­tion to those of us con­stantly seek­ing bet­ter per­for­mance from our apps, but it’s impor­tant to keep a cou­ple of things in mind too:

  • mak­ing a func­tion or method inline does not always guar­an­tee a per­for­mance improvement
  • overuse can add sig­nif­i­cant bloat and makes your assem­bly big­ger and takes longer to load, hence poten­tially imped­ing over­all performance
  • always measure/profile your app first, don’t pre­ma­turely optimize

Fur­ther readings

MSDN – Sta­t­i­cally resolved type para­me­ters (pre­ceded by a caret ^ symbol)

MSDN – Inline functions

Sta­t­i­cally typed duck typ­ing in F#

Share

Prob­lem

The square root of 2 can be writ­ten as an infi­nite con­tin­ued fraction.

image7

The infi­nite con­tin­ued frac­tion can be writ­ten, ?2 = [1;(2)], (2) indi­cates that 2 repeats ad infini­tum. In a sim­i­lar way, ?23 = [4;(1,3,1,8)].

It turns out that the sequence of par­tial val­ues of con­tin­ued frac­tions for square roots pro­vide the best ratio­nal approx­i­ma­tions. Let us con­sider the con­ver­gents for ?2.

image11

Hence the sequence of the first ten con­ver­gents for ?2 are:

1, 3/2, 7/5, 17/12, 41/29, 99/70, 239/169, 577/408, 1393/985, 3363/2378, …

What is most sur­pris­ing is that the impor­tant math­e­mat­i­cal constant,

e = [2; 1,2,1, 1,4,1, 1,6,1 , … , 1,2k,1, …].

The first ten terms in the sequence of con­ver­gents for e are:

2, 3, 8/3, 11/4, 19/7, 87/32, 106/39, 193/71, 1264/465, 1457/536, …

The sum of dig­its in the numer­a­tor of the 10th con­ver­gent is 1+4+5+7=17.

Find the sum of dig­its in the numer­a­tor of the 100th con­ver­gent of the con­tin­ued frac­tion for e.

Solu­tion

If you look at the con­ver­gents of ?2 and the numer­a­tors in the con­ver­gents of e, you’ll see a pat­tern emerging:

1    +    2    *   1    =    3

2    +    3    *   2    =    8

3    +    8    *   1    =    11

8    +   11   *   1    =    19

11  +   19   *   4    =    87

If you look at the sequence of numer­a­tors in the con­ver­gents of e ( 2, 3, 8, 11, … ) and the sequence of num­bers in the con­ver­gents of ?2 ( 1, 2, 1, 1, 4, 1, … ), given the cur­rent numer­a­tor ( n ) and the pre­vi­ous numer­a­tor ( n-1 ) in the sequence and the cor­re­spond­ing num­ber in the con­ver­gents of ?2 ( i )the next numer­a­tor ( n+1 ) can be cal­cu­lated using the formula:

( n+1) = ( n-1 ) + n * i

Once we have this for­mula to work with, the rest is sim­ple, the solu­tion runs in 7 mil­lisec­onds on my machine.

Share

Prob­lem

Con­sider the frac­tion, n/d, where n and d are pos­i­tive inte­gers. If n < d and HCF(n,d)=1, it is called a reduced proper fraction.

If we list the set of reduced proper frac­tions for d <= 8 in ascend­ing order of size, we get:

1/8, 1/7, 1/6, 1/5, 1/4, 2/7, 1/3, 3/8, 2/5, 3/7, 1/2, 4/7, 3/5, 5/8, 2/3, 5/7, 3/4, 4/5, 5/6, 6/7, 7/8

It can be seen that 2/5 is the frac­tion imme­di­ately to the left of 3/7.

By list­ing the set of reduced proper frac­tions for d <= 1,000,000 in ascend­ing order of size, find the numer­a­tor of the frac­tion imme­di­ately to the left of 3/7.

Solu­tion

This prob­lem is fairly easy, given that the answer we’re look­ing for much be very close to 3 / 7 (0.4285714286) I sim­ply iter­ate through the denom­i­na­tors, d, and find the clos­est numer­a­tor, n, which will pro­duce a value less than 3 / 7. Then fil­ter the set so we end up with only the n, d pairs that have a GCD of 1 and pick the numer­a­tor from the n, d pair whose n / d frac­tion is the biggest.

Share

Prob­lem

Each char­ac­ter on a com­puter is assigned a unique code and the pre­ferred stan­dard is ASCII (Amer­i­can Stan­dard Code for Infor­ma­tion Inter­change). For exam­ple, upper­case A = 65, aster­isk (*) = 42, and low­er­case k = 107.

A mod­ern encryp­tion method is to take a text file, con­vert the bytes to ASCII, then XOR each byte with a given value, taken from a secret key. The advan­tage with the XOR func­tion is that using the same encryp­tion key on the cipher text, restores the plain text; for exam­ple, 65 XOR 42 = 107, then 107 XOR 42 = 65.

For unbreak­able encryp­tion, the key is the same length as the plain text mes­sage, and the key is made up of ran­dom bytes. The user would keep the encrypted mes­sage and the encryp­tion key in dif­fer­ent loca­tions, and with­out both “halves”, it is impos­si­ble to decrypt the message.

Unfor­tu­nately, this method is imprac­ti­cal for most users, so the mod­i­fied method is to use a pass­word as a key. If the pass­word is shorter than the mes­sage, which is likely, the key is repeated cycli­cally through­out the mes­sage. The bal­ance for this method is using a suf­fi­ciently long pass­word key for secu­rity, but short enough to be memorable.

Your task has been made easy, as the encryp­tion key con­sists of three lower case char­ac­ters. Using cipher1.txt (right click and ‘Save Link/Target As…’), a file con­tain­ing the encrypted ASCII codes, and the knowl­edge that the plain text must con­tain com­mon Eng­lish words, decrypt the mes­sage and find the sum of the ASCII val­ues in the orig­i­nal text.

Solu­tion

Share

Prob­lem

A com­mon secu­rity method used for online bank­ing is to ask the user for three ran­dom char­ac­ters from a pass­code. For exam­ple, if the pass­code was 531278, they may ask for the 2nd, 3rd, and 5th char­ac­ters; the expected reply would be: 317.

The text file, keylog.txt, con­tains fifty suc­cess­ful login attempts.

Given that the three char­ac­ters are always asked for in order, analyse the file so as to deter­mine the short­est pos­si­ble secret pass­code of unknown length.

Solu­tion

This prob­lem is actu­ally solved much eas­ier by hand with pen and paper, but regard­less here’s a F# solu­tion to the problem.

Share