Skip to content

Literature Review

Louis Kueh edited this page Jan 18, 2019 · 18 revisions

Literature Review

Thoughts

  • lots of info especially in HLint and Scala which I current don't understand. Would like to spend some time investigating why some rules exist and how they can be applied to F#.
  • Timescale: better to look for new ideas or learn F# now, or both equally?
  • hard to come up with novel ideas
  • Most analysers have a specific case they are looking for (stylistic). Haven't found analyser with novel solutions.

Features of desired analyzer

Learning guidelines

  • feature to warn user when using immutable code (only do functional language for learning) and can be switched on/off
  • TODO: think of more ways to implement some form of teaching based on user code
    • e.g. record common beginner problems patterns, and give suggestions and explanations as to when they occur
    • Perhaps different levels to set, based on beginner.
      • A level 1 beginner - catch and explain why F# variables are immutable when they assign variables - from experience using Elixir
      • A level 2 - might explain why it's better to use a mapFold instead of a loop but not mutable variables
      • ..
    • Essentially a tutorial like system that will enable beginners to learn by doing F#

Finding probable bugs

  • TODO: investigate different ways in which a function might give an incorrect heuristic based on a pervious error in the program
  • error after function ends (e.g. missing bracket, mismatched brackets)
  • names of variable indicate what program is doing
    • NLP to process naming conventions and derive meaning
      • Give user option to view derived meaning/input derived meaning of function
      • check code against this derived meaning
      • However code naming needs to be verbose
    • ML/AI to base on others people code with same name
      • has pitfalls with names that don't give information - e.g. foo()
    • something along the lines of how Gmail asks if you forgot an attachment when you mention it in the email. Apply to F# functions.

Testing

  • Automatically generate unit tests for a given function
    • can be used in conjuction with NLP to process naming conventions
    • Possibly test function for edge cases such as null and check if it throws an exception

Locating dead code

  • If condition that never goes into (e.g. if (false))
  • Infinite while loop

Detecting performance issues

  • turn on performance optimisation -> use mutable in certain cases resource
    • however wrap them in immutable interfaces
    • wrap in classes for more complex data sets

Improving code structure and maintainability

  • Refactor complex expressioons
    • Currently thinking how. Simple heuristic would be number of lines/characters in a function. Might have better way to do it - e.g. look for duplicated code and suggest refactoring into a function
  • Replace anon functions with subfunctions
  • Unifcation, is there any other alternative that would be better e.g. concat (map f x) ==> concatMap f x
    • Better way of doing certain things
      • e.g. if using a for loop could use map
      • Use built in libraries of F#
  • Curried functions do not label their arguments.
    • let funcWithApplication =printfn "My name is %s and I am %d years old!"
    • Explanation: At the call site, tooltips will not give you meaningful information as to what the string and int input types actually represent. If you encounter point-free code like funcWithApplication that is publicly consumable, it is recommended to do a full η-expansion so that tooling can pick up on meaningful names for arguments.
    • Furthermore, debugging point-free code can be challenging, if not impossible. Debugging tools rely on values bound to names (for example, let bindings) so that you can inspect intermediate values midway through execution. When your code has no values to inspect, there is nothing to debug. In the future, debugging tools may evolve to synthesize these values based on previously executed paths, but it's not a good idea to hedge your bets on potential debugging functionality.
  • Exception handling via active patterns let (|Even|Odd|) input = if input % 2 = 0 then Even else Odd
    • Reconciling functionality to perform in the face of an exception with pattern matching can be a bit tricky if you wish to keep the code clean. One such way to handle this is to use active patterns as a means to group functionality surrounding an error case with an exception itself. For example, you may be consuming an API that, when it throws an exception, encloses valuable information in the exception metadata. Unwrapping a useful value in the body of the captured exception inside the Active Pattern and returning that value can be helpful in some situations.
  • Do not use monadic error handling to replace exception - aka use exceptions when needed
    • They contain detailed diagnostic information, which is very helpful when debugging an issue.
    • They are well-understood by the runtime and other .NET languages.
    • They can reduce significant boilerplate when compared with code that goes out of its way to avoid exceptions by implementing some subset of their semantics on an ad-hoc basis.
  • Object oriented programming
    • Composition over inheritance is a long-standing idiom that good F# code can adhere to. The fundamental principle is that you should not expose a base class and force callers to inherit from that base class to get functionality.
    • Avoid these features
      • Inheritance-based type hierarchies and implementation inheritance
      • Nulls and Unchecked.defaultof<_>
    • Use object expressions to implement interfaces if you don't need a class
  • For lambdas and folds Hlint has many rules regarding these topics e.g.
    • f (x:xs) = negate x + f xs ; f [] = 0 -- f xs = foldr ((+) . negate) 0 xs
    • f (x:xs) = x + 1 : f xs ; f [] = [] -- f xs = map (+ 1) xs
    • f z (x:xs) = f (z*x) xs ; f z [] = z -- f z xs = foldl (*) z xs

Styling

  • Conforming to coding guidelines and standards (styling)
    • bracket reduction, bracket rotation
  • Conforming to specifications

Useful guidelines

  • Improve code and teach author better style. Doing certain modifications one by one individually improves style (Hlint)
  • Ignore/suppress hints based on user input, as hints do not always make sense
  • exit status for users to immediately know what error has occured
consistency:  1
design:       2
readability:  4
refactor:     8
warning:     16

So 12 means readability + reafactoring. In practice for F# discriminated unions could be useful.

Refs

Clone this wiki locally