Skip to content

Frequently Asked Questions

cetinsert edited this page May 30, 2012 · 19 revisions

Why a functional programming language?

I'm not familiar with functional languages such as f# or Hascall, are there any specific reasons you selected this language for the development of the proxy?? Im guessing that they are better somehow in writing systems with a high level of concurrency?? Also, if one were to write this in a language like c#, how would the process be different??

I started development of PortFusion in both F# and C# in 2011. At that time the functionality was split into two separate executables. So there are C# code files available in this package: http://sourceforge.net/projects/portfusion/files/0.9.3/PortFusionSource.7z/download

Main Reasons for Using Functional Programming

Conciseness and Type Inference

C#

public static int Foo(int x, int y) { return x + y; }
  • Lots of noise: public static int ( int int ) { return ; }
  • Restrictions: Foo must be part of a class
  • Weakness: Foo cannot be declared in a way to work with any type that supports addition

F#

let foo x y = x + y

Haskell

foo x y = x + y

-- or --

foo = (+)

Pattern Matching

C#

Arguments.Skip(2).Select(Connection.Parse)

public static Connection Parse(string mapping)
{
  var m = mapping.Split('=', ':');
  return new Connection() { ServerPort = int.Parse(m[0]), Relay = new DnsEndPoint(m[1], int.Parse(m[2])) };
}

6 lines of code, can only parse very old syntax Port=Host:Port for a single PortFusion task (ancient reverse proxy mode in 0.9.3)

Haskell

parse :: [String] -> [Task]
parse [         "]", ap, "["         ] = [(:><:) $ read ap                                         ]
parse [ lp, lh, "-", fp, fh, "[", ap ] = [(read lp, B.pack lh) :-<: ((read fp, B.pack fh),read ap) ]
parse [ ap, "]", fh, fp, "-", rh, rp ] = [read ap :>-: ((B.pack fh, read fp), (B.pack rh, read rp))]
parse [ ap, "]",         "-", rh, rp ] = [read ap :>=:                        (B.pack rh, read rp) ]
parse m = concatMap parse $ map (map B.unpack . filter (not . B.null) . B.split ' ' . B.pack) m

6 lines of code in 1.1, parses all 4 tasks as well as their joint usage as a single command line

Main Reasons for Haskell

  • resulting binaries are native code and do not depend on the presence of a large .NET runtime; this is extremely important for supporting Linux, OS X, FreeBSD and other operating systems
  • application uses one order of magnitude less memory
  • application can scale way better (see Why Haskell?); concurrency and parallelism are natural in Haskell and do not require having to wait for or learn the new async layer in .NET 4.5 (which adds just more noise as now one has to track two lists of APIs for each class: one for asynchronous methods and one for synchronous)
  • code is much cleaner and shorter than F#; F# uses .NET libraries which are not designed for functional programming languages, Haskell libraries are much more idiomatic of the functional programming paradigm and enable increased brevity

Summing up

if one were to write this in a language like c#, how would the process be different??

If I used C# for PortFusion, it would

  • have an incredible amount of syntactic noise
  • have much longer source code
  • not be easily refactorable due to incredible amount of noise one would have to carry around for each change
  • require unnatural ways to achieve great scalability (also true for F#, due to .NET class libraries)
  • use lots of RAM (also true for F#)
  • depend on a large virtual machine (also true for F#)
  • be extremely difficult to support on Linux, OS X, FreeBSD and other operating systems as I would have to ask every potential user to install Mono, which many people unfortunately see as an abomination (also true for F#)
  • not be interactively testable

Oh and some can find more faults with C#

From: http://flyingfrogblog.blogspot.com/2012/05/whats-wrong-with-c.html

I link to places in the main Haskell source file of PortFusion (as it stood on 2012-05-30) which would be otherwise severely affected because of the following undesirable properties of C#:

null everywhere; const nowhere; Equality and comparison are a mess: you've got System.IComparable and Equals but then you've also got: System.IComparable<_> System.IEquatableSystem.Collections.IComparer System.Collections.IStructuralComparable System.Collections.IStructuralEquatable System.Collections.Generic.IComparer System.Collections.Generic.IEqualityComparer; Tuples should be structs but structs unnecessarily inhibit tail call elimination so one of the most common and fundamental data types will allocate unnecessarily and destroy scalable parallelism.

as well as

No pattern matching, crippled switch statement, no language-level inlining, no language-integrated tuples, no free functions, no records/discriminated unions, no units of measure, no object expressions, no first-class functions, no "everything is an expression", no useful type inference, no compositioning/pipelining, no automatic generalization, no code quotations, no custom operators, no generalized type extensions, ...


Contact

corsis

[email protected]