Hacker News new | ask | show | jobs
by lispm 2628 days ago
> you need to box the variables (carry type information in addition to the value).

Dealing with boxing/unboxing and trying to minimize boxing operations in computations is regularly done in Lisp compilers.

> It is possible to introduce new variables in the global scope from a local scope

just like in Lisp. Generally Javascript and Lisp have a lot in common. Scoping rules are different though and Lisp is not object-oriented at the core - but provides closures or adds object-oriented extensions like CLOS which are semi-optional.

  * (defun f ()
      (setf a 5))
  ; in: DEFUN F
  ;     (SETF A 5)
  ; ==>
  ;   (SETQ A 5)
  ; 
  ; caught WARNING:
  ;   undefined variable: COMMON-LISP-USER::A
  ; 
  ; compilation unit finished
  ;   Undefined variable:
  ;     A
  ;   caught 1 WARNING condition
  F


  * (defun g ()
      (print a))
  ; in: DEFUN G
  ;     (PRINT A)
  ; 
  ; caught WARNING:
  ;   undefined variable: COMMON-LISP-USER::A
  ; 
  ; compilation unit finished
  ;   Undefined variable:
  ;     A
  ;   caught 1 WARNING condition

As you can see the compiler warns about undefined variables, but deals with it.

  * (if (> (random 1.0) 0.5) (f))
  5
  * (g)

  5 
  5
If we remove the binding of A, then we get a runtime error.

  * (makunbound 'a)
  A
  * (g)

  debugger invoked on a UNBOUND-VARIABLE in thread
  #<THREAD "main thread" RUNNING {10005205B3}>:
    The variable A is unbound.

  Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.

  restarts (invokable by number or by possibly-abbreviated name):
    0: [CONTINUE   ] Retry using A.
    1: [USE-VALUE  ] Use specified value.
    2: [STORE-VALUE] Set specified value and use it.
    3: [ABORT      ] Exit debugger, returning to top level.

  (G)
     source: (PRINT A)
  0] 
As one can see, both F and G are actually compiled machine code functions. Both functions we directly AOT compiled to machine code when I entered them at the prompt.

  * (disassemble #'f)
  ; disassembly for F
  ; Size: 38 bytes. Origin: #x226D3C9C
  ; 9C:       498B4540         MOV RAX, [R13+64]                ; no-arg-parsing entry point
                                                                ; thread.binding-stack-pointer
  ; A0:       488945F8         MOV [RBP-8], RAX
  ; A4:       488B15A5FFFFFF   MOV RDX, [RIP-91]                ; 'A
  ; AB:       BF0A000000       MOV EDI, 10
  ; B0:       B904000000       MOV ECX, 4
  ; B5:       FF7508           PUSH QWORD PTR [RBP+8]
  ; B8:       B898914F22       MOV EAX, #x224F9198              ; #<FDEFN SET>
  ; BD:       FFE0             JMP RAX
  ; BF:       0F0B0F           BREAK 15                         ; Invalid argument count trap
  NIL
  * (disassemble #'g)
  ; disassembly for G
  ; Size: 57 bytes. Origin: #x226D3D3C
  ; 3C:       498B4540         MOV RAX, [R13+64]                ; no-arg-parsing entry point
                                                                ; thread.binding-stack-pointer
  ; 40:       488945F8         MOV [RBP-8], RAX
  ; 44:       488B05A5FFFFFF   MOV RAX, [RIP-91]                ; 'A
  ; 4B:       8B50F5           MOV EDX, [RAX-11]
  ; 4E:       4A8B142A         MOV RDX, [RDX+R13]
  ; 52:       83FA61           CMP EDX, 97
  ; 55:       480F4450F9       CMOVEQ RDX, [RAX-7]
  ; 5A:       83FA51           CMP EDX, 81
  ; 5D:       7412             JEQ L0
  ; 5F:       B902000000       MOV ECX, 2
  ; 64:       FF7508           PUSH QWORD PTR [RBP+8]
  ; 67:       B838555422       MOV EAX, #x22545538              ; #<FDEFN PRINT>
  ; 6C:       FFE0             JMP RAX
  ; 6E:       0F0B0F           BREAK 15                         ; Invalid argument count trap
  ; 71: L0:   0F0B17           BREAK 23                         ; UNBOUND-SYMBOL-ERROR
  ; 74:       00               BYTE #X00                        ; RAX
  NIL