Là macro hỗ trợ trong một ngôn ngữ lập trình được coi là có hại?


8

Sự lạm dụng đầu tiên xuất hiện trong đầu tôi ở C là:

#define if while 

Nhưng đồng thời nó vô cùng tiện dụng và mạnh mẽ khi được sử dụng đúng cách.

Một cái gì đó tương tự xảy ra với các macro Lisp thông thường.

Tại sao tất cả các ngôn ngữ lập trình không hỗ trợ các macro như thế này và các lựa chọn thay thế là gì?

Có phải chúng được coi là có hại?


20
Dao là nguy hiểm. Một cách khác là thử cắt mọi thứ bằng thìa.
Matt Ellen


1
@Matt hoặc để cung cấp xử lý tốt.
OscarRyz

Câu trả lời:


15

Tôi có ý kiến ​​rằng nếu một ngôn ngữ có macro, thì chúng phải là một phần được lập kế hoạch tốt và là một phần không thể thiếu của ngôn ngữ chứ không phải của trình biên dịch .

Ví dụ, hệ thống vĩ mô của Lisp là một tính năng ngôn ngữ tích hợp rất mạnh mẽ và tuân theo tất cả các quy tắc và quy định của chính Lisp.

Ví dụ ngược lại, hệ thống macro C / C ++ tách biệt với ngôn ngữ và được tích hợp vào trình biên dịch. Kết quả là bạn không bị giới hạn trong các ràng buộc của ngôn ngữ của mình và có thể tạo mã không hợp lệ và xác định lại các từ khóa cụ thể của ngôn ngữ.

Vào cuối ngày, có một số ngôn ngữ không có tính năng vĩ mô - nhưng những ngôn ngữ đó không bị bỏ sót nhiều. Tất cả phụ thuộc vào mức độ biểu cảm của một ngôn ngữ và liệu nó có cách tiếp cận thay thế cho lập trình meta hay không. Lập trình meta chỉ là một cách để đảm bảo rằng khi bạn thực hiện X, X được thực hiện theo cùng một cách trong suốt ứng dụng.


4
Tệ hơn, bộ tiền xử lý C thậm chí không phải là một phần của trình biên dịch.

1
Sự khác biệt bạn đang cố gắng rút ra ở đây giữa "ngôn ngữ" và "trình biên dịch" là gì? Hệ thống macro của C được định nghĩa trong tiêu chuẩn ngôn ngữ, trên thực tế, các macro của Lisp được mở rộng bởi trình biên dịch Lisp và bất kỳ triển khai ngôn ngữ nào cũng được xác định, khi tất cả được nói và thực hiện, bởi trình biên dịch và các thư viện chuẩn. Do đó, cụm từ "tách biệt với ngôn ngữ và được tích hợp vào trình biên dịch" là vô nghĩa. Có lẽ điểm khác biệt mà bạn đang tìm kiếm là các macro C được triển khai trong giao diện người biên dịch và macro Lisp ở mặt sau?
Mason Wheeler

Sự khác biệt phải làm với sự thống nhất của ngôn ngữ. Hãy nghĩ về nó theo cách này, bạn đang lên kế hoạch đi nước ngoài và bạn phải học nói tiếng Pháp để đi đến những nơi và mua thức ăn. Khi làm việc với hải quan, bạn cũng phải học tiếng Thụy Điển hoặc chỉ giao dịch với tiếng Pháp. Các macro tiền biên dịch C khác nhau về mặt cú pháp và ngữ pháp so với tiêu chuẩn C. Thử thách nhận thức sau đó tìm ra những gì ngôn ngữ khác sẽ làm với chương trình C tiêu chuẩn của bạn. Trong một số trường hợp, điều đó thật dễ dàng, nhưng tôi đã xem toàn bộ cụm từ mã là một định nghĩa vĩ mô. Bây giờ gỡ lỗi nó.
Berin Loritsch

8

Macro C và macro Lisp hoàn toàn khác nhau. Các macro C được mở rộng bằng cách sử dụng thay thế chuỗi trước khi thực hiện bất kỳ xử lý nào khác. Các macro Lisp được mở rộng sau khi văn bản đầu vào được phân tích cú pháp thành cây cú pháp 1 và có thể sử dụng toàn bộ ngôn ngữ trong quá trình mở rộng. Với macro Lisp, bạn không chỉ có thể làm những điều ngu ngốc như #define begin {, mà bạn có thể xác định cấu trúc điều khiển của riêng mình và thậm chí cư trú các mảng tại thời gian biên dịch bằng cách sử dụng bất kỳ mã nào bạn muốn.

Một lý do cho việc không bao gồm các macro là mọi thứ phức tạp hơn thay thế chuỗi đơn giản có thể rất khó để làm việc với các ngôn ngữ có cú pháp kiểu C. Một khiếu nại khác về macro là chúng có thể làm cho mã khó đọc hơn, điều này có thể đúng nếu không được thực hiện một cách khéo léo. Các macro Lisp được viết tốt thực sự có thể làm cho mã dễ đọc hơn.

1 ngoại trừ các macro đọc, được mở rộng trong quá trình tạo cây cú pháp.


2

Tôi không nghĩ có một lý do cụ thể tại sao họ không được hỗ trợ trong một số ngôn ngữ, giống như lý do tại sao một số trường hợp nhạy cảm và một số không. Không có lý do thực sự thường, chỉ là một quyết định đã được đưa ra.

NHƯNG lý do họ không bao gồm chắc chắn không phải là bảo mật. Các

#define X Y

câu lệnh thay đổi tất cả X thành Y tại thời điểm biên dịch. Nếu bạn có thể thay đổi các câu lệnh #define, bạn có thể sao chép / thay thế nguồn bạn quan tâm để thay đổi và biên dịch lại.

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.