Các bộ cài đặt Ruby - dù được tạo bằng (c)attr_accessor
cách thủ công hay bằng tay - dường như là các phương thức duy nhất cần self.
đủ điều kiện khi được truy cập trong chính lớp đó. Điều này dường như chỉ đặt Ruby vào thế giới ngôn ngữ:
- Tất cả các phương thức cần
self
/this
(như Perl, và tôi nghĩ Javascript) - Không có phương thức nào yêu cầu
self
/this
is (C #, Java) - Chỉ những người thiết lập mới cần
self
/this
(Ruby?)
So sánh tốt nhất là C # và Ruby, vì cả hai ngôn ngữ đều hỗ trợ các phương thức truy cập hoạt động theo cú pháp giống như các biến cá thể của lớp: foo.x = y
, y = foo.x
. C # gọi chúng là thuộc tính.
Đây là một ví dụ đơn giản; chương trình tương tự trong Ruby rồi đến C #:
class A
def qwerty; @q; end # manual getter
def qwerty=(value); @q = value; end # manual setter, but attr_accessor is same
def asdf; self.qwerty = 4; end # "self." is necessary in ruby?
def xxx; asdf; end # we can invoke nonsetters w/o "self."
def dump; puts "qwerty = #{qwerty}"; end
end
a = A.new
a.xxx
a.dump
lấy đi self.qwerty =()
và nó không thành công (Ruby 1.8.6 trên Linux & OS X). Bây giờ C #:
using System;
public class A {
public A() {}
int q;
public int qwerty {
get { return q; }
set { q = value; }
}
public void asdf() { qwerty = 4; } // C# setters work w/o "this."
public void xxx() { asdf(); } // are just like other methods
public void dump() { Console.WriteLine("qwerty = {0}", qwerty); }
}
public class Test {
public static void Main() {
A a = new A();
a.xxx();
a.dump();
}
}
Câu hỏi: Điều này có đúng không? Có những dịp nào khác ngoài những người thiết lập mà bản thân là cần thiết? Tức là, có những trường hợp nào khác mà một phương thức Ruby không thể được gọi mà không có bản thân nó?
Chắc chắn có rất nhiều trường hợp mà bản thân trở nên cần thiết. Đây không phải là duy nhất đối với Ruby, chỉ cần rõ ràng:
using System;
public class A {
public A() {}
public int test { get { return 4; }}
public int useVariable() {
int test = 5;
return test;
}
public int useMethod() {
int test = 5;
return this.test;
}
}
public class Test {
public static void Main() {
A a = new A();
Console.WriteLine("{0}", a.useVariable()); // prints 5
Console.WriteLine("{0}", a.useMethod()); // prints 4
}
}
Cùng một sự mơ hồ được giải quyết theo cùng một cách. Nhưng trong khi tinh tế, tôi đang hỏi về trường hợp
- Một phương pháp đã được xác định, và
- Không có biến cục bộ nào được xác định và
Chúng ta gặp phải
qwerty = 4
không rõ ràng — đây là một lệnh gọi phương thức hay một phép gán biến cục bộ mới?
@Mike Stone
Chào! Tôi hiểu và đánh giá cao những điểm bạn đã làm và ví dụ của bạn thật tuyệt. Hãy tin tôi khi tôi nói, nếu tôi có đủ danh tiếng, tôi sẽ bỏ phiếu cho câu trả lời của bạn. Tuy nhiên, chúng tôi vẫn không đồng ý:
- về vấn đề ngữ nghĩa, và
- về điểm trung tâm của thực tế
Đầu tiên tôi khẳng định, không phải không có sự mỉa mai, chúng ta đang có một cuộc tranh luận ngữ nghĩa về ý nghĩa của 'sự mơ hồ'.
Khi nói đến phân tích cú pháp và ngữ nghĩa ngôn ngữ lập trình (chủ đề của câu hỏi này), chắc chắn bạn sẽ thừa nhận một phổ rộng của khái niệm 'sự mơ hồ'. Hãy chỉ áp dụng một số ký hiệu ngẫu nhiên:
- mơ hồ: mơ hồ về từ vựng (lex phải 'nhìn về phía trước')
- Mơ hồ: mơ hồ về ngữ pháp (yacc phải trì hoãn phân tích cây phân tích cú pháp)
- AMBIGUOUS: sự mơ hồ khi biết mọi thứ tại thời điểm thực thi
(và có cả rác từ 2-3 nữa). Tất cả các danh mục này được giải quyết bằng cách thu thập thêm thông tin theo ngữ cảnh, ngày càng tìm kiếm nhiều hơn trên toàn cầu. Vì vậy, khi bạn nói,
"qwerty = 4" là UNAMBIGUOUS trong C # khi không có biến nào được xác định ...
Tôi không thể đồng ý hơn. Nhưng cũng tương tự, tôi đang nói
"qwerty = 4" là không rõ ràng trong ruby (vì nó hiện đang tồn tại)
"qwerty = 4" không rõ ràng trong C #
Và chúng tôi vẫn chưa mâu thuẫn với nhau. Cuối cùng, đây là nơi chúng tôi thực sự không đồng ý: Có thể hoặc không thể triển khai ruby mà không có bất kỳ cấu trúc ngôn ngữ nào khác như vậy,
Đối với "qwerty = 4", ruby UNAMBIGUOUSLY gọi một setter hiện có nếu
không có biến cục bộ nào được xác định
Bạn nói không. Tôi nói "có; một ruby khác có thể tồn tại hoạt động giống hệt như hiện tại ở mọi khía cạnh, ngoại trừ "qwerty = 4" xác định một biến mới khi không có setter nào và không có cục bộ nào tồn tại, nó gọi setter nếu có tồn tại và gán cho cục bộ nếu có. Tôi hoàn toàn chấp nhận rằng tôi có thể sai. Trên thực tế, một lý do tại sao tôi có thể sai sẽ rất thú vị.
Hãy để tôi giải thích.
Hãy tưởng tượng bạn đang viết một ngôn ngữ OO mới với các phương thức truy cập giống như các bản sao (như ruby & C #). Có thể bạn sẽ bắt đầu với những ngữ pháp khái niệm như:
var = expr // assignment
method = expr // setter method invocation
Nhưng trình biên dịch phân tích cú pháp (thậm chí không phải thời gian chạy) sẽ bị lỗi, bởi vì ngay cả sau khi tất cả các đầu vào được kiểm tra, không có cách nào để biết ngữ pháp nào phù hợp. Bạn đang phải đối mặt với một sự lựa chọn cổ điển. Tôi không thể chắc chắn về các chi tiết, nhưng về cơ bản ruby làm được điều này:
var = expr // assignment (new or existing)
// method = expr, disallow setter method invocation without .
đó là lý do tại sao nó không mơ hồ, trong khi và C # thực hiện điều này:
symbol = expr // push 'symbol=' onto parse tree and decide later
// if local variable is def'd somewhere in scope: assignment
// else if a setter is def'd in scope: invocation
Đối với C #, 'sau' vẫn đang ở thời gian biên dịch.
Tôi chắc rằng ruby cũng có thể làm như vậy, nhưng 'sau' sẽ phải ở trong thời gian chạy, vì như ben đã chỉ ra, bạn không biết cho đến khi câu lệnh được thực thi thì trường hợp nào áp dụng.
Câu hỏi của tôi không bao giờ có ý nghĩa "tôi có thực sự cần 'cái tôi' không?" hoặc "điều gì có thể tránh được sự mơ hồ?" Thay vì tôi muốn biết tại sao lại có sự lựa chọn cụ thể này? Có lẽ đó không phải là hiệu suất. Có thể nó vừa hoàn thành công việc, hoặc tốt nhất là luôn cho phép cục bộ 1 lót ghi đè một phương thức (một yêu cầu trường hợp khá hiếm) ...
Nhưng tôi gợi ý rằng ngôn ngữ động nhất có thể là ngôn ngữ trì hoãn quyết định này lâu nhất và chọn ngữ nghĩa dựa trên thông tin theo ngữ cảnh nhất: vì vậy nếu bạn không có ngôn ngữ cục bộ và bạn đã xác định một setter, nó sẽ sử dụng setter . Đây không phải là lý do tại sao chúng ta thích ruby, smalltalk, objc, bởi vì việc gọi phương thức được quyết định trong thời gian chạy, mang lại khả năng biểu cảm tối đa?
$this->
khi truy cập các biến cá thể. Đó là chuyến đi của tôi mọi lúc.