Những cạm bẫy tiềm năng của việc cho phép liên kết từ vựng cho bộ đệm là gì?


12

Điều này đã được lấy cảm hứng từ cuộc thảo luận về từ vựng ràng buộc vs vựng-let trong câu hỏi này . Vì ràng buộc từ vựng cung cấp cho bạn khả năng đóng cửa hữu ích mà mọi người có thể sử dụng trong các ngôn ngữ khác như JavaScript, tại sao bạn không bật nó mọi lúc?

Giả sử khả năng tương thích ngược với Emacsen cũ không phải là vấn đề bạn nên tìm kiếm những cạm bẫy nào nếu bật nó trong bộ đệm mã kế thừa?

Câu trả lời:


13

Một cái bẫy chính là ngữ nghĩa bắt buộc đối với xác định các biến biến-tức là không được định nghĩa với defvarvà bạn bè thay đổi với lexical-binding: Nếu không có nó, letliên kết mọi sự năng động, nhưng với lexical-bindingcác biến không xác định được kích hoạt đang bị ràng buộc lexically , và thậm chí elided hoàn toàn nếu không sử dụng trong phạm vi từ vựng hiện tại .

Mã cũ đôi khi dựa vào điều này. Để tránh phụ thuộc cứng cho các tính năng tùy chọn, nó liên kết các biến động mà không yêu cầu thư viện tương ứng hoặc tự khai báo biến đó:

(let ((cook-eggs-enabled t))
  (cook-my-meal))

Nếu tính năng nấu là tùy chọn, chúng tôi không muốn buộc các phụ thuộc không cần thiết vào người dùng, vì vậy chúng tôi không sử dụng (require 'cook)và thay vào đó dựa vào tự động tải cook-my-mealchức năng.

Rõ ràng đối với người đọc cook-eggs-enabledkhông phải là biến cục bộ, nhưng vẫn đề cập đến một số biến động toàn cầu từ cookthư viện ở đây. Không có lexical-bindingmã này hoạt động như dự định: cook-eggs-enabledbị ràng buộc động, cho dù được xác định hay không.

Với lexical-bindingtuy nhiên, nó phá vỡ: cook-eggs-enabledhiện đang bị ràng buộc lexically (và sau đó tối ưu hóa đi, bởi vì nó không được sử dụng), do biến động toàn cầu cook-eggs-enabledkhông bao giờ chạm chút nào và vẫn nil do thời gian cook-my-mealđược gọi, vì vậy chúng tôi ngạc nhiên sẽ không có bất kỳ trứng trong bữa ăn của chúng tôi

May mắn thay, những vấn đề này rất dễ phát hiện : Trình biên dịch byte cảnh báo một cách tự nhiên về một ràng buộc từ vựng không sử dụng ở đây.

Cách khắc phục rất đơn giản: Hoặc thêm một (require 'cook)(đối với các tính năng không thực sự là tùy chọn nào), hoặc để tránh phụ thuộc cứng, khai báo biến là biến động trong mã của riêng bạn . Có một defvarhình thức đặc biệt cho việc này:

(defvar cook-eggs-enabled)

Điều này định nghĩa cook-eggs-enabledlà biến động, nhưng không ảnh hưởng đến chuỗi doc, load-history(và do đó find-variablevà bạn bè) hoặc bất cứ điều gì khác, ngoại trừ bản chất ràng buộc của biến.


Trong trường hợp năng động, sẽ không phải là đoạn mã nguyên nhân cook-eggs-enabledđược cởi ra khi letkết thúc? Tôi khá chắc chắn rằng tôi đã gặp phải một lỗi như thế này trước đây. Defvar đã xảy ra bên trong letletsau đó khôi phục biến về trạng thái ban đầu (void).
Malabarba

1
@Malababa Không, đó là một tình huống khác. Xem đoạn cuối của Xác định biến cho lý do.
lunaryorn
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.