Skip to content

Instantly share code, notes, and snippets.

@keleshev
Last active February 11, 2024 18:18
Show Gist options
  • Save keleshev/764edad011a6a7a40da11716b19ddb75 to your computer and use it in GitHub Desktop.
Save keleshev/764edad011a6a7a40da11716b19ddb75 to your computer and use it in GitHub Desktop.

Comparision of JaneStreet Base and OCaml Stdlib

How to use Base

Either use Base selectively:

# #show List.hd;;
val hd : 'a list -> 'a

# #show Stdlib.List.hd;;
val hd : 'a list -> 'a

# #show Base.List.hd;;
val hd : 'a list -> 'a option

Opening Base shadows existing module, which are still accessible with the fully-qualified path.

# open Base;;

# #show List.hd;;
val hd : 'a list -> 'a option

# #show Stdlib.List.hd;;
val hd : 'a list -> 'a
# int_of_char;;
Warning 3: deprecated: Base.int_of_char
[2016-09] this element comes from the stdlib distributed with OCaml.
Use [Char.to_int] instead.
- : char -> int = <fun>

# Stdlib.int_of_char;;
- : char -> int = <fun>

Base deprecates:

  • Polymorphic comparison functions (next slide)
  • I/O functions (more on this later)
  • Missplaced functions: Char.to_int vs int_of_char

1. Comparison: monomorphic vs. polymorphic

(* Stdlib *)
val (=): 'a -> 'a -> bool (* Polymorhpic! *)
val (>): 'a -> 'a -> bool (* Polymorphic! *)
val (+): int -> int -> int

open Base
val (=): int -> int -> bool
val (>): int -> int -> bool
val (+): int -> int -> int

(* Also Base *)
Float.O.(=): float -> float -> bool
Float.O.(>): float -> float -> bool
Float.O.(+): float -> float -> float

Labelled parameters

# #show Stdlib.String.concat;;
val concat : string -> string list -> string

# #show Stdlib.StdLabels.String.concat;;
val concat : ?sep:string -> string list -> string

# #show Base.String.concat;;
val concat : ?sep:string -> string list -> string
# Stdlib.List.map;;
- : ('a -> 'b) -> 'a list -> 'b list = <fun>

# Stdlib.StdLabels.List.map;;
- : 'a list -> f:('a -> 'b) -> 'b list = <fun>

# Base.List.map;;
- : 'a list -> f:('a -> 'b) -> 'b list = <fun>

Total functions are preffered

# #show Stdlib.List.hd;;
val hd : 'a list -> 'a

# #show Base.List.hd;;
val hd : 'a list -> 'a option

# #show Base.List.hd_exn;;
val hd_exn : 'a list -> 'a

Stack-safe functions

# let big_list = Base.List.init 100_000_000 (fun _ -> 1);;
val big_list : int Base.List.t =
  [1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1;
   1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1;
   1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1;
   1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1;
   1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; 1; ...]

# Base.List.map ~f:succ big_list;;
- : int Base.List.t =
[2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2;
 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2;
 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2;
 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2;
 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; ...]
 
# Stdlib.List.map succ big_list;;
Stack overflow during evaluation (looping recursion?).
Raised by primitive operation at file "//toplevel//", line 5, characters 32-39
Called from file "//toplevel//", line 5, characters 32-39
Called from file "//toplevel//", line 5, characters 32-39
Called from file "//toplevel//", line 5, characters 32-39
Called from file "//toplevel//", line 5, characters 32-39
Called from file "//toplevel//", line 5, characters 32-39
Called from file "//toplevel//", line 5, characters 32-39
Called from file "//toplevel//", line 5, characters 32-39
Called from file "//toplevel//", line 5, characters 32-39
Called from file "//toplevel//", line 5, characters 32-39
Called from file "//toplevel//", line 5, characters 32-39
Called from file "//toplevel//", line 5, characters 32-39
Called from file "//toplevel//", line 5, characters 32-39
Called from file "//toplevel//", line 5, characters 32-39
Called from file "//toplevel//", line 5, characters 32-39
Called from file "//toplevel//", line 5, characters 32-39
Called from file "//toplevel//", line 5, characters 32-39
Called from file "//toplevel//", line 5, characters 32-39
Called from file "//toplevel//", line 5, characters 32-39
Called from file "//toplevel//", line 5, characters 32-39
Called from file "//toplevel//", line 5, characters 32-39
Called from file "//toplevel//", line 5, characters 32-39
Called from file "//toplevel//", line 5, characters 32-39
...

Modules common to Base and Stdlib

And their type equality

✅Array
✅Bool
✅Buffer
✅Bytes
✅Char
✅Float
➖Fn/Fun
❌Hashtbl
✅Int
✅Int32
✅Int64
✅Lazy
✅List
❌Map
✅Nativeint
✅Option
✅Printf
❌Sequence/Seq
✅Linked_queue/Queue
➖Random
✅Result
❌Set
❌Stack
✅String
➖Sys
✅Uchar
✅Unit

Base-only modules

Applicative
Avltree
Backtrace
Binary_search
Binary_searchable
Blit
Comparable
Comparator
Comparisons
Container
Continue_or_stop
Either
Error
Equal
Exn
Field
Floatable
Formatter
Hash
Hash_set
Hashable
Hasher
Identifiable
Indexed_container
Info
Int63
Intable
Invariant
Maybe_bound
Monad
Option_array
Or_error
Ordered_collection_common
Ordering
Poly
Polymorphic_compare
Popcount
Pretty_printer
Queue (array-based queue, unlike the Linked_queue)
Ref
Sexp
Sexpable
Sign
Sign_or_nan
Source_code_position
Staged
Stringable
T
Type_equal
Uniform_array
Validate
Variant
With_return
Word_size

Stdlib-only modules

Arg
Bigarray
Callback
Complex
Condition
Digest
Dynlink
Ephemeron
Event
Filename
Format
Gc
Genlex
Lexing
Marshal
Mutex
Obj
Oo
Parsing
Pervasives
Printexc
Scanf
Spacetime
Str
Stream
Thread
ThreadUnix
Unix
Weak

Note, some private modules like Stdlib.CamlinternalFormat and Base.Not_exposed_properly were omitted.

Functors vs. first-class modules

# module StringMap = Stdlib.Map.Make (Stdlib.String);;
module StringMap : ...

# let m = StringMap.empty;;
val m : 'a StringMap.t = <abstr>

# StringMap.add "x" 2 m;;
- : int StringMap.t = <abstr>
# let m = Base.Map.empty (module Base.String);;
val m : (string, 'a, Base.String.comparator_witness) Base.Map.t = <abstr>

# Base.Map.add m ~key:"x" ~data:1;;
- : (string, int, Base.String.comparator_witness) Base.Map.t Base.Map.Or_duplicate.t = `Ok <abstr>

Summary

  • Advantages

    • Safety
      • Stack safety
      • Exceptions safety
      • Monomorphic comparison
      • Async/blocking IO separation
    • Documentation
      • API documentation
      • Real World OCaml book
  • Disadvantages

    • We have to use it
    • We have to get it approved
    • We have to audit it
@rbjorklin
Copy link

This is excellent, thank you!

Caught a minor error in the Total functions are preferred section:

# #show Base.List.hd_exn;;
val hd : 'a list -> 'a option

should have been:

# #show Base.List.hd_exn;;
val hd_exn : 'a list -> 'a

@keleshev
Copy link
Author

@rbjorklin, thanks, fixed!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment