rotor a tool for renaming values in ocaml s module system
play

Rotor: A Tool for Renaming Values in OCamls Module System Reuben N. - PowerPoint PPT Presentation

Rotor: A Tool for Renaming Values in OCamls Module System Reuben N. S. Rowe, Hugo Fre, Simon J. Thompson, Scott Owens University of Kent, Canterbury Third International Workshop on Refactoring Tuesday 28 th May 2019, Montral, Canada


  1. Rotor: A Tool for Renaming Values in OCaml’s Module System Reuben N. S. Rowe, Hugo Férée, Simon J. Thompson, Scott Owens University of Kent, Canterbury Third International Workshop on Refactoring Tuesday 28 th May 2019, Montréal, Canada

  2. Why OCaml? • OCaml is a functional programming language • It is industrially relevant • Used by over 50 companies • 600 publicly released pacakges/libraries • > 11,000 open source projects • The module system presents interesting challenges • No existing tool support for refactoring 1/10

  3. Renaming: A First Step • Only substitute identifiers (no new code) • Preserve behaviour/correctness (incl. compilability) • Keep the footprint minimal (not simply ‘replace all’) • This requires a ‘whole program’ analysis 2/10

  4. Renaming in OCaml is Hard! Expressiveness of the module system introduce complications: • Explicit module type annotations (i.e. interfaces) • Module and module type aliasing • Module type constraints • Functors 3/10 • Module and module type include

  5. Example: Module Includes and Aliases module A = struct let bar = "hello" end let bar = "world" end module C = ( A : sig val foo : int end ) ;; print_int ( A .foo + B .foo + C .foo) ;; print_string ( A .bar ^ " " ^ B .bar) ;; 4/10 let foo = 2 module B = struct include A

  6. Example: Module Includes and Aliases module A = struct let bar = "hello" end let bar = "world" end module C = ( A : sig val foo : int end ) ;; print_int ( A .foo + B .foo + C .foo) ;; print_string ( A .bar ^ " " ^ B .bar) ;; 4/10 let foo = 2 module B = struct include A

  7. Example: Module Includes and Aliases module A = struct let bar = "hello" end let bar = "world" end module C = ( A : sig val foo : int end ) ;; print_int ( A .foo + B .foo + C .foo) ;; print_string ( A .bar ^ " " ^ B .bar) ;; 4/10 let foo = 2 module B = struct include A

  8. Example: Module Includes and Aliases module A = struct let bar = "hello" end let bar = "world" end module C = ( A : sig val foo : int end ) ;; print_int ( A .foo + B .foo + C .foo) ;; print_string ( A .bar ^ " " ^ B .bar) ;; reference to parent module 4/10 let foo = 2 module B = struct include A

  9. Example: Module Includes and Aliases module A = struct let bar = "hello" end let bar = "world" end module C = ( A : sig val foo : int end ) ;; print_int ( A .foo + B .foo + C .foo) ;; print_string ( A .bar ^ " " ^ B .bar) ;; reference to parent module 4/10 let foo = 2 module B = struct include A

  10. Example: Module Includes and Aliases module A = struct let bar = "hello" end let bar = "world" end module C = ( A : sig val foo : int end ) ;; print_int ( A .foo + B .foo + C .foo) ;; print_string ( A .bar ^ " " ^ B .bar) ;; reference to parent module 4/10 let foo = 2 module B = struct include A

  11. Example: Module Includes and Aliases module A = struct let bar = "hello" end let bar = "world" end module C = ( A : sig val foo : int end ) ;; print_int ( A .foo + B .foo + C .foo) ;; print_string ( A .bar ^ " " ^ B .bar) ;; 4/10 let foo = 2 module B = struct include A

  12. Example: Module Includes and Aliases module A = struct let bar = "hello" end let bar = "world" end module C = ( A : sig val foo : int end ) ;; print_int ( A .foo + B .foo + C .foo) ;; print_string ( A .bar ^ " " ^ B .bar) ;; 4/10 let foo = 2 module B = struct include A

  13. Example: Module Includes and Aliases module A = struct let bar = "hello" end let bar = "world" end module C = ( A : sig val foo : int end ) ;; print_int ( A .foo + B .foo + C .foo) ;; print_string ( A .bar ^ " " ^ B .bar) ;; dependencies: A.foo , B.foo , C.foo 4/10 let foo = 2 module B = struct include A

  14. Example: Functors type t = int print_endline ( P .to_string (5, "Gold Rings!")) ;; module P = Pair ( Int )( String ) ;; end let to_string s = s module String = struct end let to_string i = string_of_int i 5/10 module type Stringable = sig end ( X .to_string x) ^ " " ^ ( Y .to_string y) let to_string (x, y) = module Pair ( X : Stringable )( Y : Stringable ) = struct end val to_string : t -> string type t type t = X .t * Y .t module Int = struct type t = string

  15. Example: Functors type t = int print_endline ( P .to_string (5, "Gold Rings!")) ;; module P = Pair ( Int )( String ) ;; end let to_string s = s module String = struct end let to_string i = string_of_int i 5/10 module type Stringable = sig end ( X .to_string x) ^ " " ^ ( Y .to_string y) let to_string (x, y) = module Pair ( X : Stringable )( Y : Stringable ) = struct end val to_string : t -> string type t type t = X .t * Y .t module Int = struct type t = string

  16. Example: Functors type t = int print_endline ( P .to_string (5, "Gold Rings!")) ;; module P = Pair ( Int )( String ) ;; end let to_string s = s module String = struct end let to_string i = string_of_int i 5/10 module type Stringable = sig end ( X .to_string x) ^ " " ^ ( Y .to_string y) let to_string (x, y) = module Pair ( X : Stringable )( Y : Stringable ) = struct end val to_string : t -> string type t type t = X .t * Y .t module Int = struct type t = string

  17. Example: Functors type t = int print_endline ( P .to_string (5, "Gold Rings!")) ;; module P = Pair ( Int )( String ) ;; end let to_string s = s module String = struct end let to_string i = string_of_int i 5/10 module type Stringable = sig end ( X .to_string x) ^ " " ^ ( Y .to_string y) let to_string (x, y) = module Pair ( X : Stringable )( Y : Stringable ) = struct end val to_string : t -> string type t type t = X .t * Y .t module Int = struct type t = string

  18. Example: Functors type t = int print_endline ( P .to_string (5, "Gold Rings!")) ;; module P = Pair ( Int )( String ) ;; end let to_string s = s module String = struct end let to_string i = string_of_int i 5/10 module type Stringable = sig end ( X .to_string x) ^ " " ^ ( Y .to_string y) let to_string (x, y) = module Pair ( X : Stringable )( Y : Stringable ) = struct end val to_string : t -> string type t type t = X .t * Y .t module Int = struct type t = string

  19. Example: Functors type t = int print_endline ( P .to_string (5, "Gold Rings!")) ;; module P = Pair ( Int )( String ) ;; end let to_string s = s module String = struct end let to_string i = string_of_int i 5/10 module type Stringable = sig end ( X .to_string x) ^ " " ^ ( Y .to_string y) let to_string (x, y) = module Pair ( X : Stringable )( Y : Stringable ) = struct end val to_string : t -> string type t type t = X .t * Y .t module Int = struct type t = string

  20. Example: Functors type t = int print_endline ( P .to_string (5, "Gold Rings!")) ;; module P = Pair ( Int )( String ) ;; end let to_string s = s module String = struct end let to_string i = string_of_int i 5/10 module type Stringable = sig end ( X .to_string x) ^ " " ^ ( Y .to_string y) let to_string (x, y) = module Pair ( X : Stringable )( Y : Stringable ) = struct end val to_string : t -> string type t type t = X .t * Y .t module Int = struct type t = string

  21. Example: Functors type t = int print_endline ( P .to_string (5, "Gold Rings!")) ;; module P = Pair ( Int )( String ) ;; end let to_string s = s module String = struct end let to_string i = string_of_int i 5/10 module type Stringable = sig end ( X .to_string x) ^ " " ^ ( Y .to_string y) let to_string (x, y) = module Pair ( X : Stringable )( Y : Stringable ) = struct end val to_string : t -> string type t type t = X .t * Y .t module Int = struct type t = string

  22. Example: Functors module type Stringable = sig Stringable.to_string , Pair[1].to_string , Pair[2].to_string Int.to_string , String.to_string , dependencies: print_endline ( P .to_string (5, "Gold Rings!")) ;; module P = Pair ( Int )( String ) ;; end let to_string s = s module String = struct end let to_string i = string_of_int i type t = int end ( X .to_string x) ^ " " ^ ( Y .to_string y) let to_string (x, y) = module Pair ( X : Stringable )( Y : Stringable ) = struct end val to_string : t -> string 5/10 type t type t = X .t * Y .t module Int = struct type t = string

  23. Rotor: Main Features • Implemented in OCaml itself • Visitor classes used to manipulate ASTs • Performs fine-grained module dependency analysis • Outputs detailed information on renaming dependencies 6/10

  24. Experimental Evaluation • OCaml compiler (~500 files, ~2650 test cases) • Re-compilation successful for 70% of cases • Jane Street standard library overlay (~900 files, ~3000 test cases) • Re-compilation successful for 37% of cases • 46% fail due to use of language preprocessor • 5% require changes in external libraries 7/10

  25. Experimental Evaluation Mean Deps Avg. Hunks/File Max 50 128 1127 5.7 5.0 Files 7.5 24.0 1.3 Mode 3 3 19 1.0 Hunks Jane Street Standard Library Overlay OCaml Compiler Codebase 15.0 Files Hunks Deps Avg. Hunks/File Max 19 59 35 Mean 1.0 3.8 5.9 1.6 1.5 Mode 3 3 1 8/10

  26. Conclusions • Big impact for automatic refactoring in functional programming • OCaml’s module system introduces much complexity • Much work still to be done! 9/10 • Require a notion of refactoring dependency

Download Presentation
Download Policy: The content available on the website is offered to you 'AS IS' for your personal information and use only. It cannot be commercialized, licensed, or distributed on other websites without prior consent from the author. To download a presentation, simply click this link. If you encounter any difficulties during the download process, it's possible that the publisher has removed the file from their server.

Recommend


More recommend