Slide 1

Slide 1 text

Manuel M T Chakravarty University of New South Wales Foreign Inline Code in Haskell mchakravarty TacticalGrace justtesting.org 1 Tuesday, 9 September 14 25 minute time slot: 20min talking + 5min [10min The Problem; 10min Inline Objective-C by Example] » I like to show you a new way for Haskell to play nicely with other programming languages. » I will demonstrate this at the example of Objective-C, but the same idea works for other languages as well.

Slide 2

Slide 2 text

2 Tuesday, 9 September 14 » Imagine you want to write a great new app in Haskell!

Slide 3

Slide 3 text

2 Tuesday, 9 September 14 » Imagine you want to write a great new app in Haskell!

Slide 4

Slide 4 text

λ 3 Tuesday, 9 September 14 » ...then you will need to use many existing frameworks and libraries. » Luckily, Haskell has a versatile foreign function interface as well as supporting tools.

Slide 5

Slide 5 text

“Problem solved?” 4 Tuesday, 9 September 14 » Does that solve the problem of language interoperability? » Let me explain that at an example...

Slide 6

Slide 6 text

“Problem solved?” No! 4 Tuesday, 9 September 14 » Does that solve the problem of language interoperability? » Let me explain that at an example...

Slide 7

Slide 7 text

dumpURL :: String -> IO () dumpURL urlString = do urlData <- stringWithContentsOfUrl urlString putStr urlData What we want to write 5 Tuesday, 9 September 14 * Kind of fair enough, after all the API we want to call —here, Cocoa— presents this interface.

Slide 8

Slide 8 text

dumpURL :: String -> IO () dumpURL urlString = do urlData <- stringWithContentsOfUrl urlString putStr urlData What we want to write char *stringWithContentsOfUrlCstub(char *urlString) { NSURL *url = [NSURL URLWithString:urlString]; [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:NULL]; } What we want to call (& need to put into an extra file) 5 Tuesday, 9 September 14 * Kind of fair enough, after all the API we want to call —here, Cocoa— presents this interface.

Slide 9

Slide 9 text

What we have to write as well… foreign import stringWithContentsOfURLCstub :: CString -> IO CString stringWithContentsOfURL :: String -> IO String stringWithContentsOfURL url = withCString url $ \urlC -> do resultC <- stringWithContentsOfURLCstub urlC result <- peek resultC free resultC return result 6 Tuesday, 9 September 14 » FFI code: If you find it confusing, that’s fine, as I want to argue that you shouldn’t write it in the first place. * Anything extensively relying on foreign frameworks will be a pain [Hybrid languages (eg, F# & Scala) have a different set of trade offs and focus on one foreign language, but don’t necessarily solve this problem either.]

Slide 10

Slide 10 text

Bridging Libraries 1-to-1 transliteration of types & functions 7 Tuesday, 9 September 14 * Bridging or binding libraries transliterate types & functions * Need to be maintained and documented; track multiple versions of base library * Lack of type safety * Tools and dynamic transliteration (by reflection) help

Slide 11

Slide 11 text

C➙Haskell c2hs A case study GTK+ 8 Tuesday, 9 September 14 * c2hs: automation for bridging C libraries to Haskell * Implements large parts of a C compiler front-end * Bridge for the cross-platform Gnome GUI library GTK+

Slide 12

Slide 12 text

9 Tuesday, 9 September 14 * AFAIK, currently the only fully featured and properly maintained Haskell GUI library * Haskell GTK+ library is used for realistic applications

Slide 13

Slide 13 text

“Does this approach scale?” 10 Tuesday, 9 September 14 » Read question * It requires significant resources & constant effort to track the original library * Application frameworks: enormous and growing footprint

Slide 14

Slide 14 text

February 2011 Introduction of GTK+ 3 11 Tuesday, 9 September 14 * Base GTK+ development isn’t even particularly fast * Bridging libraries lag behind their base libraries * Another example: Haskell OpenGL library

Slide 15

Slide 15 text

February 2011 Introduction of GTK+ 3 December 2013 GTK+ 3 in Haskell Bridge 11 Tuesday, 9 September 14 * Base GTK+ development isn’t even particularly fast * Bridging libraries lag behind their base libraries * Another example: Haskell OpenGL library

Slide 16

Slide 16 text

12 Tuesday, 9 September 14 * Compared to modern application frameworks, GTK+ is small!

Slide 17

Slide 17 text

Bridging libraries don’t scale Too much weight! 13 Tuesday, 9 September 14

Slide 18

Slide 18 text

“Interoperability is an old problem — maybe an old solution can help?” 14 Tuesday, 9 September 14

Slide 19

Slide 19 text

15 Tuesday, 9 September 14 * Modula-2 with inline 68000 assembly * Assembly code can symbolically refer to Modula-2 entities (e.g., variables)

Slide 20

Slide 20 text

15 Tuesday, 9 September 14 * Modula-2 with inline 68000 assembly * Assembly code can symbolically refer to Modula-2 entities (e.g., variables)

Slide 21

Slide 21 text

15 Tuesday, 9 September 14 * Modula-2 with inline 68000 assembly * Assembly code can symbolically refer to Modula-2 entities (e.g., variables)

Slide 22

Slide 22 text

“Inline C, C++, Objective-C, … in Haskell?” 16 Tuesday, 9 September 14 * We don’t want to build front ends for a few more languages into GHC * How do we share entities between the languages?

Slide 23

Slide 23 text

HASKELL WORKSHOP 2002 HASKELL WORKSHOP 2007 17 Tuesday, 9 September 14 » We use Template Haskell's general quasi-quotation support…

Slide 24

Slide 24 text

dumpURL :: String -> IO () dumpURL urlString = do urlData <- stringWithContentsOfUrl urlString putStr urlData What we want to write char *stringWithContentsOfUrlCstub(char *urlString) { return ; } What we want to call (& need to put into an extra file) [NSString stringWithContentsOfURL: [NSURL URLWithString:urlString] encoding:NSUTF8StringEncoding error:NULL] 18 Tuesday, 9 September 14 » Let's go back to out initial example of reading from a URL… » …and inline the Objective-C code into Haskell.

Slide 25

Slide 25 text

dumpURL :: String -> IO () dumpURL urlString = do urlData <- stringWithContentsOfUrl urlString putStr urlData char *stringWithContentsOfUrlCstub(char *urlString) { return ; } [NSString stringWithContentsOfURL: [NSURL URLWithString:urlString] encoding:NSUTF8StringEncoding error:NULL] stringWithContentsOfUrl stringWithContentsOfUrl 18 Tuesday, 9 September 14 » Let's go back to out initial example of reading from a URL… » …and inline the Objective-C code into Haskell.

Slide 26

Slide 26 text

[NSString stringWithContentsOfURL: [NSURL URLWithString:urlString] encoding:NSUTF8StringEncoding error:NULL] putStr urlData dumpURL :: String -> IO () dumpURL urlString = do urlData <- 19 Tuesday, 9 September 14

Slide 27

Slide 27 text

[NSString stringWithContentsOfURL: [NSURL URLWithString:urlString] encoding:NSUTF8StringEncoding error:NULL] putStr urlData dumpURL :: String -> IO () dumpURL urlString = do urlData <- 20 Tuesday, 9 September 14

Slide 28

Slide 28 text

Language.C.Inline dumpURL :: String -> IO () dumpURL urlString = do urlData <- putStr urlData [NSString stringWithContentsOfURL: [NSURL URLWithString:urlString] encoding:NSUTF8StringEncoding error:NULL] 21 Tuesday, 9 September 14 * Inline Objective-C * To have Objective-C in the middle of a Haskell function definition, we use a quasiquoter for C & Objective-C

Slide 29

Slide 29 text

Language.C.Inline dumpURL :: String -> IO () dumpURL urlString = do urlData <- putStr urlData [NSString stringWithContentsOfURL: [NSURL URLWithString:urlString] encoding:NSUTF8StringEncoding error:NULL] [cexp| |] quasiquoted Objective-C 21 Tuesday, 9 September 14 * Inline Objective-C * To have Objective-C in the middle of a Haskell function definition, we use a quasiquoter for C & Objective-C

Slide 30

Slide 30 text

Language.C.Inline dumpURL :: String -> IO () dumpURL urlString = do urlData <- putStr urlData [NSString stringWithContentsOfURL: [NSURL URLWithString:urlString] encoding:NSUTF8StringEncoding error:NULL] [cexp| |] quasiquoted Objective-C 22 Tuesday, 9 September 14 * Inline Objective-C * We need to specify the types of marshalled values, because… * (a) GHC 7.8’s TH provides less type information and (b) we may want custom marshalling

Slide 31

Slide 31 text

Language.C.Inline dumpURL :: String -> IO () dumpURL urlString = do urlData <- putStr urlData [NSString stringWithContentsOfURL: [NSURL URLWithString:urlString] encoding:NSUTF8StringEncoding error:NULL] [cexp| |] $(objc [’urlString :> ''String] $ ''String <: ) inline Objective-C splice 22 Tuesday, 9 September 14 * Inline Objective-C * We need to specify the types of marshalled values, because… * (a) GHC 7.8’s TH provides less type information and (b) we may want custom marshalling

Slide 32

Slide 32 text

Language.C.Inline dumpURL :: String -> IO () dumpURL urlString = do urlData <- putStr urlData [NSString stringWithContentsOfURL: [NSURL URLWithString:urlString] encoding:NSUTF8StringEncoding error:NULL] [cexp| |] $(objc [’urlString :> ''String] $ ''String <: ) inline Objective-C splice marshalled arguments 22 Tuesday, 9 September 14 * Inline Objective-C * We need to specify the types of marshalled values, because… * (a) GHC 7.8’s TH provides less type information and (b) we may want custom marshalling

Slide 33

Slide 33 text

Language.C.Inline dumpURL :: String -> IO () dumpURL urlString = do urlData <- putStr urlData [NSString stringWithContentsOfURL: [NSURL URLWithString:urlString] encoding:NSUTF8StringEncoding error:NULL] [cexp| |] $(objc [’urlString :> ''String] $ ''String <: ) inline Objective-C splice marshalled arguments marshalled result 22 Tuesday, 9 September 14 * Inline Objective-C * We need to specify the types of marshalled values, because… * (a) GHC 7.8’s TH provides less type information and (b) we may want custom marshalling

Slide 34

Slide 34 text

[cexp| |] $(objc [’urlString :> ''String] $ ''String <: ) … 23 Tuesday, 9 September 14 * All the FFI code is generated automatically

Slide 35

Slide 35 text

[cexp| |] $(objc [’urlString :> ''String] $ ''String <: ) … foreign import stringWithContentsOfURLCstub :: CString -> IO CString stringWithContentsOfURL :: String -> IO String stringWithContentsOfURL url = withCString url $ \urlC -> do resultC <- stringWithContentsOfURLCstub urlC result <- peek resultC free resultC return result generated 23 Tuesday, 9 September 14 * All the FFI code is generated automatically

Slide 36

Slide 36 text

“Isn’t this supposed to be a demo?” 24 Tuesday, 9 September 14 * Run through https://github.com/mchakravarty/language-c-inline/tree/master/tests/objc/ concept * make & execute

Slide 37

Slide 37 text

Marshalling records type Point = (Float, Float) newtype Vector = Vector (Float, Float) data Particle = Particle { mass :: Float , loc :: Point , vel :: Vector , acc :: Vector } 25 Tuesday, 9 September 14 * A common problem is exchanging data between Haskell and Objective-C.

Slide 38

Slide 38 text

“How do we turn this into an object?” 26 Tuesday, 9 September 14 * Run through https://github.com/mchakravarty/language-c-inline/tree/master/tests/objc/ record * Make & run * Show generated Objective-C interface

Slide 39

Slide 39 text

Embedding Haskell 27 Tuesday, 9 September 14 * Run through https://github.com/mchakravarty/language-c-inline/tree/master/tests/objc/ app * Make & run

Slide 40

Slide 40 text

28 Tuesday, 9 September 14

Slide 41

Slide 41 text

Language integration by language inlining https://github.com/mchakravarty/language-c-inline cabal install language-c-inline 29 Tuesday, 9 September 14 * Lack of bridge saves a lot of work; instant access to new versions * Bridges require familiarity with native libraries already; inline code leverages that directly * Haskell types are automatically mapped to types of the inlined language

Slide 42

Slide 42 text

Thank you! 30 Tuesday, 9 September 14

Slide 43

Slide 43 text

Images from http://wikimedia.org http://openclipart.org GitHub repo https://github.com/mchakravarty/language-c-inline Megamax Modula-2 Screenshot by Dirk Steins 31 Tuesday, 9 September 14