From 79dd7f85720d2402634304530d446f24b920839d Mon Sep 17 00:00:00 2001 From: Grant Shangreaux Date: Tue, 12 Jul 2022 16:34:53 -0500 Subject: Add: scopes-and-bindings talk --- scopes/#foo.rb# | 3 + scopes/bindings-and-scopes.org | 214 +++++++++++++++++++++++++++++++++++++++++ scopes/lspace.rb | 21 ++++ 3 files changed, 238 insertions(+) create mode 100755 scopes/#foo.rb# create mode 100755 scopes/bindings-and-scopes.org create mode 100755 scopes/lspace.rb diff --git a/scopes/#foo.rb# b/scopes/#foo.rb# new file mode 100755 index 0000000..92d1b69 --- /dev/null +++ b/scopes/#foo.rb# @@ -0,0 +1,3 @@ +def goo(x) + +end \ No newline at end of file diff --git a/scopes/bindings-and-scopes.org b/scopes/bindings-and-scopes.org new file mode 100755 index 0000000..b1b5633 --- /dev/null +++ b/scopes/bindings-and-scopes.org @@ -0,0 +1,214 @@ +#+TITLE: Bindings and Scopes +#+AUTHOR: Grant Shangreaux + +* Definitions +** What is a "Binding"? + + - 𝑓(x) = x²; x = 10 ⟵ "binding" the value 10 to x (sort of) + - an identifier that acts as a reference to some place in memory + that can be "bound" to a specific value. entity, object, etc. + + #+begin_src ruby + x = 5 # binding the variable name x to the value 5 + + def square(x) + x * x + end + + # here the argument 10 binds to the x variable in the method body + square(10) + #+end_src + +** /Scope/ of Variable Bindings + + *Scope* refers to /where/ in the source code an identifer can + be accessed. Where is something visible? + + *Lexical Scope* is the textual scope defined in the source code + + *Indefinite Scope* a reference can be used anywhere in the + program. the value of the reference is determined at runtime + +** /Extent/ of Variable Bindings + + *Extent* refers to /when/, as the program is executing, + the binding exists. + + *Indefinite Extent* binding persists as long as a possibility + of reference remains. GC and Closures + + *Dynamic Extent* binding is established and disestablished + explicitly. Stack-like nested runtime constructs + +** Types of Bindings + + *Lexical bindings* have /lexical scope/ and /indefinite extent/ + + *Dynamic bindings* have /indefinite scope/ and /dynamic extent/ + +* Ruby + +Ruby, like most modern languages, uses /lexical binding/. +Each new textual part of source code creates a new lexical scope. +~Kernel.binding~ will return the ~Binding~ object of the current scope + +** Scope Gates + + A new scope is entered any time you: + - define a class with ~class SomeClass~ + - define a module with ~module SomeModule~ + - define a method with ~def some_method~ + + Old scope is no longer available + +** Scope Gate Example + +#+begin_src ruby :results output +v0 = 0 +class SomeClass # Scope gate + v1 = 1 + p local_variables # As the name says, it gives you all local variables in scope + + def some_method # Scope gate + v2 = 2 + p local_variables + end # end of def scope gate +end # end of class scope gate + +some_class = SomeClass.new +some_class.some_method +#+end_src + +#+RESULTS: +: [:v1] +: [:v2] + +** Breaking Scope Gates! + + - define a class using ~Class.new~ + - define a module using ~Module.new~ + - define a method with ~define_method~ + +** Breaking Scope Gate Example + +#+begin_src ruby :results output +v0 = 0 +SomeClass = Class.new do + v1 = 1 + p local_variables + + define_method(:some_method) do + v2 = 2 + p local_variables + end +end + +some_class = SomeClass.new +some_class.some_method +#+end_src + +#+RESULTS: +: [:v1, :v0, :some_class] +: [:v2, :v1, :v0, :some_class] + +** Closures + +#+begin_src ruby :results output + i = 0 + + counter = lambda do + puts i + i += 1 + end + i = 10 + 3.times { counter.call } +#+end_src + +#+RESULTS: +: 10 +: 11 +: 12 + +** Quiz + +#+begin_src ruby + class SomeClass + b = 'hello' + @@m = 'hi' + + def initialize + @some_var = 1 + c = 'hi' + end + + def some_method + # what bindings are available here? + a = 'hello' + end + end + + some_object = SomeClass.new + some_object.some_method +#+end_src + +* Emacs Lisp + +Until recently, everything was dynamically scoped. + +New code is adopting lexical binding as much as possible. + +Dynamic Scope is *powerful* and enhances extensibility. + +** Special Variables + +#+begin_src emacs-lisp :results output + (defvar *special* 'i-am-special) + + (defun print-special () + (print *special*)) + + (let ((*special* 'lookee-here)) + (print-special)) + + (print-special) +#+end_src + +** Lexical Binding + +#+begin_src emacs-lisp :results output + (setq normal 'i-am-normal) + + (defun print-normal () + (print normal)) + + (let ((normal 'does-this-work?)) + (print-normal)) + + (print-normal) +#+end_src + +** symbol-value + +(symbol-value SYMBOL) + + This function does not change global state, including the match data. + +Return SYMBOL’s value. Error if that is void. +Note that if ‘lexical-binding’ is in effect, this returns the +global value outside of any lexical scope. + +** lexical-binding + + Automatically becomes buffer-local when set. + This variable is safe as a file local variable if its value + satisfies the predicate ‘booleanp’. + Probably introduced at or before Emacs version 24.1. + +Documentation: +Whether to use lexical binding when evaluating code. +Non-nil means that the code in the current buffer should be evaluated +with lexical binding. +This variable is automatically set from the file variables of an +interpreted Lisp file read using ‘load’. Unlike other file local +variables, this must be set in the first line of a file. + diff --git a/scopes/lspace.rb b/scopes/lspace.rb new file mode 100755 index 0000000..cf027e1 --- /dev/null +++ b/scopes/lspace.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require 'lspace' + +def log(str) + puts "#{LSpace[:log_prefix]}: #{str}" +end + +def handle_request(req) + LSpace.with(log_prefix: "handling request") do + log Time.now + log req[:status] + log req[:body] + end + + Lspace.with(log_prefix: "app") do + log "request handled" + end +end + +handle_request({status: 200, body: "success!"}) -- cgit v1.2.3