มีหลายสิ่งที่ 'เรียบร้อย' ที่สามารถทำได้ในภาษาแบบไดนามิกที่สามารถซ่อนอยู่ในส่วนของรหัสที่ไม่ชัดเจนในทันทีสำหรับโปรแกรมเมอร์หรือผู้ตรวจสอบบัญชีคนอื่น ๆ เกี่ยวกับการทำงานของรหัสที่กำหนด
พิจารณาลำดับนี้ใน irb (เปลือกทับทิมแบบโต้ตอบ):
irb(main):001:0> "bar".foo
NoMethodError: undefined method `foo' for "bar":String
from (irb):1
from /usr/bin/irb:12:in `<main>'
irb(main):002:0> class String
irb(main):003:1> def foo
irb(main):004:2> "foobar!"
irb(main):005:2> end
irb(main):006:1> end
=> nil
irb(main):007:0> "bar".foo
=> "foobar!"
เกิดอะไรขึ้นฉันพยายามโทรหาเมธอดfoo
ในค่าคงที่สตริง สิ่งนี้ล้มเหลว ฉันเปิดคลาส String ขึ้นมาแล้วกำหนดเมธอดfoo
o คืนค่า"foobar!"
แล้วเรียกมันว่า สิ่งนี้ใช้ได้ผล
สิ่งนี้เรียกว่าคลาสเปิดและทำให้ฉันฝันร้ายทุกครั้งที่ฉันคิดว่าการเขียนโค้ดด้วยทับทิมซึ่งมีความปลอดภัยหรือความสมบูรณ์แบบใด ๆ แน่นอนว่ามันช่วยให้คุณทำสิ่งต่าง ๆ ได้อย่างรวดเร็ว ... แต่ฉันสามารถทำให้มันทุกครั้งที่มีคนเก็บสายมันเก็บไว้ในไฟล์หรือส่งมันผ่านเครือข่าย และการนิยามใหม่ของ String เล็กน้อยนี้สามารถซ่อนไว้ที่ใดก็ได้ในรหัส
ภาษาไดนามิกอื่น ๆ อีกมากมายมีสิ่งที่คล้ายกันที่สามารถทำได้ Perl มีเน็คไท :: สเกลาร์ที่อยู่เบื้องหลังสามารถเปลี่ยนวิธีการทำงานของสเกลาร์ได้ (นี่ค่อนข้างชัดเจนและต้องใช้คำสั่งเฉพาะที่คุณสามารถเห็นได้ แต่สเกลาร์ที่ผ่านเข้ามาจากที่อื่นอาจเป็นปัญหา) หากคุณสามารถเข้าถึง Perl Cookbook ได้ให้ค้นหาสูตร 13.15 - การสร้างตัวแปรวิเศษพร้อมเน็คไท
เนื่องจากสิ่งเหล่านี้ (และอื่น ๆ มักเป็นส่วนหนึ่งของภาษาแบบไดนามิก) หลายวิธีในการวิเคราะห์แบบคงที่ของการรักษาความปลอดภัยในรหัสไม่ทำงาน Perl และ Undecidabilityแสดงให้เห็นว่านี่เป็นกรณีและชี้ให้เห็นแม้ปัญหาเล็กน้อยกับการเน้นไวยากรณ์ ( whatever / 25 ; # / ; die "this dies!";
poses ความท้าทายเพราะwhatever
สามารถกำหนดให้ใช้อาร์กิวเมนต์หรือไม่ที่รันไทม์อย่างสมบูรณ์เอาชนะไฮไลท์ไวยากรณ์หรือวิเคราะห์แบบคงที่)
สิ่งนี้จะน่าสนใจยิ่งขึ้นใน Ruby ด้วยความสามารถในการเข้าถึงสภาพแวดล้อมที่กำหนดไว้ในการปิด (ดูYouTube: การรักษา Ruby ที่เหมาะสมจาก RubyConf 2011 โดย Joshua Ballanco) ผมก็เกิดความตระหนักในวิดีโอนี้จากความคิดเห็น Ars Technica โดย MouseTheLuckyDog
พิจารณารหัสต่อไปนี้:
def mal(&block)
puts ">:)"
block.call
t = block.binding.eval('(self.methods - Object.methods).sample')
block.binding.eval <<-END
def #{t.to_s}
raise 'MWHWAHAW!'
end
END
end
class Foo
def bar
puts "bar"
end
def qux
mal do
puts "qux"
end
end
end
f = Foo.new
f.bar
f.qux
f.bar
f.qux
รหัสนี้สามารถมองเห็นได้อย่างสมบูรณ์ แต่mal
วิธีการอาจเป็นที่อื่น ... และด้วยคลาสที่เปิดแน่นอนว่ามันสามารถนิยามใหม่ได้ที่อื่น
ใช้รหัสนี้:
~ / $ ruby foo.rb
บาร์
> :)
qux
บาร์
b.rb: 20: ใน `qux ': MWHWAHAW! (การทำงานผิดพลาด)
จาก b.rb: 30: ใน `'
~ / $ ruby foo.rb
บาร์
> :)
qux
b.rb: 20: ใน `บาร์ ': MWHWAHAW! (การทำงานผิดพลาด)
จาก b.rb: 29: ใน `'
ในรหัสนี้ปิดก็สามารถที่จะเข้าถึงทุกวิธีการและการผูกอื่น ๆ ที่กำหนดไว้ในระดับที่ขอบเขตที่ มันเลือกวิธีการแบบสุ่มและกำหนดใหม่เพื่อเพิ่มข้อยกเว้น (ดูคลาสBindingใน Ruby เพื่อรับทราบว่าวัตถุนี้เข้าถึงอะไรได้บ้าง)
ตัวแปรวิธีการค่าของตัวเองและบล็อกตัววนซ้ำที่สามารถเข้าถึงได้ในบริบทนี้จะถูกเก็บรักษาไว้ทั้งหมด
เวอร์ชันที่สั้นกว่าที่แสดงการกำหนดค่าใหม่ของตัวแปร:
def mal(&block)
block.call
block.binding.eval('a = 43')
end
a = 42
puts a
mal do
puts 1
end
puts a
ซึ่งเมื่อเรียกใช้ผลิต:
42
1
43
นี่เป็นมากกว่าโอเพ่นคลาสที่ฉันกล่าวถึงข้างต้นซึ่งทำให้การวิเคราะห์แบบคงที่เป็นไปไม่ได้ สิ่งที่แสดงให้เห็นข้างต้นคือการปิดที่ถูกส่งไปที่อื่นดำเนินการกับสภาพแวดล้อมแบบเต็มตามที่กำหนดไว้สิ่งนี้เรียกว่าสภาพแวดล้อมระดับเฟิร์สคลาส (เช่นเดียวกับเมื่อคุณสามารถผ่านฟังก์ชันต่างๆได้ นี่คือสภาพแวดล้อมและการเชื่อมโยงทั้งหมดที่มีในเวลานั้น) หนึ่งสามารถกำหนดตัวแปรใด ๆที่กำหนดไว้ในขอบเขตของการปิด
ดีหรือไม่ดีบ่นเกี่ยวกับทับทิมหรือไม่ (มีการใช้งานที่ใคร ๆ ก็ต้องการที่จะได้รับในสภาพแวดล้อมของวิธีการ (ดูปลอดภัยใน Perl)) คำถาม "ทำไมทับทิมจะถูก จำกัด ในโครงการของรัฐบาล "ได้รับคำตอบจริงๆในวิดีโอที่ลิงก์ด้านบน
ระบุว่า:
- ทับทิมอนุญาตให้หนึ่งแยกสภาพแวดล้อมจากการปิดใด ๆ
- Ruby รวบรวมการเชื่อมทั้งหมดในขอบเขตของการปิด
- Ruby รักษาการเชื่อมโยงทั้งหมดเป็นแบบสดและไม่แน่นอน
- Ruby มีการเชื่อมใหม่แบบเงาการเชื่อมแบบเก่า (แทนการโคลนสภาพแวดล้อมหรือการห้ามไม่ให้เชื่อมต่อ)
ด้วยความหมายของตัวเลือกการออกแบบทั้งสี่นี้จึงเป็นไปไม่ได้ที่จะรู้ว่าโค้ดใดบ้างที่ทำ
เพิ่มเติมเกี่ยวกับเรื่องนี้สามารถอ่านได้ที่บทคัดย่อนอกรีตบล็อก โพสต์เฉพาะเป็นเรื่องเกี่ยวกับโครงการที่มีการอภิปรายดังกล่าว (เกี่ยวข้องกับ SO: ทำไม Scheme ถึงไม่สนับสนุนสภาพแวดล้อมระดับเฟิร์สคลาส )
อย่างไรก็ตามเมื่อเวลาผ่านไปฉันก็ตระหนักว่ามีความยากลำบากมากขึ้นและใช้พลังงานน้อยลงในสภาพแวดล้อมระดับเฟิร์สคลาสกว่าที่ฉันคิดไว้ ณ จุดนี้ฉันเชื่อว่าสภาพแวดล้อมระดับเฟิร์สคลาสนั้นไร้ประโยชน์ที่สุดและอันตรายที่สุด
ฉันหวังว่าส่วนนี้แสดงให้เห็นถึงแง่มุมที่เป็นอันตรายของสภาพแวดล้อมชั้นหนึ่งและทำไมมันจะถูกขอให้ลบทับทิมออกจากโซลูชั่นที่ให้ไว้ ไม่ใช่แค่ว่า Ruby เป็นภาษาไดนามิก (ดังที่ได้กล่าวไว้อีกคำตอบภาษาไดนามิกอื่น ๆ ได้รับอนุญาตในโครงการอื่น ๆ ) แต่มีปัญหาเฉพาะที่ทำให้บางภาษาไดนามิกยิ่งยากที่จะให้เหตุผล