Poperton
Poperton

Reputation: 2127

Understanding named arguments in OCaml and their scope

I'm reading OCaml source code and I'm getting confused about named arguments:

 let verify_transport_checksum ~proto ~ipv4_header ~transport_packet =
    (* note: it's not necessary to ensure padding to integral number of 16-bit fields here; ones_complement_list does this for us *)
    let check ~proto ipv4_header len =
      try
        let ph = Marshal.pseudoheader ~src:ipv4_header.src ~dst:ipv4_header.dst ~proto len in
        let calculated_checksum = Tcpip_checksum.ones_complement_list [ph ; transport_packet] in
        0 = compare 0x0000 calculated_checksum
      with
      | Invalid_argument _ -> false
    in
    match proto with
    | `TCP -> (* checksum isn't optional in tcp, but pkt must be long enough *)
      check ipv4_header ~proto (Cstruct.len transport_packet)
    | `UDP ->
      match Udp_wire.get_udp_checksum transport_packet with
      | n when (=) 0 @@ compare n 0x0000 -> true (* no checksum supplied, so the check trivially passes *)
      | _ ->
        check ipv4_header ~proto (Cstruct.len transport_packet)

I see that verify_transport_checksum is a function that has these 3 names arguments: ~proto ~ipv4_header ~transport_packet. Then, in the inside, it does let check ~proto ipv4_header len =. This is a new ~proto?

Then it does

let ph = Marshal.pseudoheader ~src:ipv4_header.src ~dst:ipv4_header.dst ~proto len in

what is this ~proto? Is it a named argument of Marshal.pseudoheader? If so, why it has no value?

Upvotes: 0

Views: 170

Answers (1)

Splingush
Splingush

Reputation: 246

This is doing label-punning: It takes some variable-binding from before, and passes it on to another function as a labeled argument of the same name and same value.

let someArg = "something";;
someFun ~someArg;;
(* is shorthand notation for *)
someFun ~someArg:someArg;;
  • verify_transport_checksum has the labelled argument ~proto.
  • It's used in the pattern matching below, to match against it, and to pass to the check.
  • The ~proto in the check-definition has the same name as before, so it can be passed through. However, it shadowes the previous binding of ~proto. If one called it (in the pattern matching below) like check ~proto:"something else here", it would have a different value. In your case, because it gets punned, it has the very same value as before.
  • Same thing happens on the Marshal.pseudoheader-call, the ~proto from check gets passed through.

Upvotes: 3

Related Questions