Exercises in Programming Style–Reflective

NOTE : read the rest of the series, or check out the source code.

If you enjoy read­ing these exer­cises then please buy Crista’s book to sup­port her work.

exercises-prog-styles-cover

Fol­low­ing on from the last post, we will look at the Reflec­tive style today.

 

Style 17 – Reflective

We’re now offi­cial­ly at the halfway mark in this series, I hope you’ve enjoyed the series thus far and today’s style is a funky one!

Constraints

  • The pro­gram has access to infor­ma­tion about itself, i.e. intro­spec­tion (see last post on how it dif­fers from reflec­tion)
  • The pro­gram can mod­i­fy itself — adding more abstrac­tions, vari­ables, etc. at run­time

 

In her exam­ple, Crista used Python’s metapro­gram­ming capa­bil­i­ties to:

  • dynam­i­cal­ly inject addi­tion­al func­tions based on the argu­ments passed into the script
  • eval these new func­tions and cap­ture the return val­ues into the run­ning appli­ca­tion

The metapro­gram­ming capa­bil­i­ties of .Net lan­guages have improved sig­nif­i­cant­ly since the avail­abil­i­ty of Roslyn and the F# com­pil­er ser­vice, but it’s still nowhere near what one can eas­i­ly do in Clo­jure, Ruby, Python and oth­er dynam­i­cal­ly typed lan­guages.

 

First, we need to go and grab the F# Com­pil­er Ser­vice pack­age from Nuget.

Then, we need to ref­er­ence it in our script and fol­low the tuto­r­i­al on embed­ding the F# Inter­ac­tive (FSI) in our appli­ca­tion:

Style17_01

Once we have an instance of FsiEval­u­a­tionS­es­sion, we’re most­ly inter­est­ed in its Eval­Ex­pres­sion method. Before we move on, let’s add anoth­er helper func­tion to deal with its result:

Style17_02

Now we can start writ­ing our code as strings, yay! 

Cou­ple of things I noticed whilst exper­i­ment­ing with the fol­low­ing:

  • you can’t open name­spaces in the source code
  • you can’t read files in the source code

which is why I used ful­ly qual­i­fied names for System.IO.File.ReadAllText, and why it’s only used in com­po­si­tion and not direct­ly invoked in the source code.

Instead, the code that’s cap­tured in the string below will return an extract­Words func­tion with the sig­na­ture

string -> string -> string[]

When we lat­er eval­u­ate it we’ll need to cast the result to that type and invoke the func­tion with the paths to the stop words file and the input file for Pride and Prej­u­dice.

Style17_03

We’ll apply the same approach and cre­ate a piece of code that returns a func­tion with the sig­na­ture :

string[] -> (string * int)[]

Style17_04

and anoth­er func­tion that’ll take the word fre­quen­cies gen­er­at­ed by the code above, sort them and print the top 25 results on screen:


Style17_05

Final­ly, all the pieces are in place.

Now, we can string every­thing togeth­er (pun intend­ed) by:

  1. eval­u­at­ing the code snip­pets above
  2. cap­ture the results and cast them to cor­re­spond­ing types
  3. invoke them with the paths to the stop words file and the input file

Style17_06

and voila!

 

You can find the source code for this exer­cise here.