Là ngoại lệ một khái niệm OOP?


37

Đọc một bài đăng ngày hôm qua, tôi nhận ra tôi không biết nhiều về nguồn gốc của các ngoại lệ. Có phải đó chỉ là một khái niệm liên quan đến OOP? Tôi có xu hướng nghĩ rằng nó là, nhưng một lần nữa có ngoại lệ cơ sở dữ liệu.


Tôi đã từng đọc rằng một "Mr Goodenuf" (hoặc tương tự) đã phát minh ra các ngoại lệ để đáp lại "đừng bận tâm, đó là Goodenuf, eh!" phong cách bắt nạt. Tôi dường như không thể tìm thấy một tài liệu tham khảo bây giờ - có thể người khác có thể. Sẽ rất thú vị khi biết ngôn ngữ nào họ được thêm vào đầu tiên.
Steve314

7
Haskell có ngoại lệ và hoàn toàn không phải là OOP
Daniel Gratzer

1
Mặc dù bản thân các ngoại lệ không hoàn toàn hướng đối tượng, nhưng thực tế phổ biến để xác định các ngoại lệ là các đối tượng và các trường hợp ném và bắt các đối tượng này rõ ràng là rất OOP.
Dougvj

Sự khác biệt giữa một ngoại lệ và GOTO sẽ là một câu hỏi thú vị.
Austin Henley

2
@Austin - làm thế nào về "mặc dù ngoại lệ ném vi phạm nguyên tắc điểm thoát duy nhất mà một số môn đệ khắt khe nhất của lập trình có cấu trúc ủng hộ là tuyệt đối, nhưng họ không cho phép luồng kiểm soát spaghetti không bị ràng buộc theo cách đó goto. Đặc biệt, mục tiêu của Việc ném được xác định theo ngữ cảnh, dựa trên việc lồng các cấu trúc khối. Như vậy, các trường hợp ngoại lệ thậm chí còn phụ thuộc vào một hình thức lập trình có cấu trúc hơi nghiêm ngặt hơn một chút trong đó nguyên tắc thoát đơn được lấy làm hướng dẫn, nhưng không phải là tuyệt đối ".
Steve314

Câu trả lời:


5

Ngoại lệ không phải là một khái niệm OOP.

Nhưng chúng không hoàn toàn không liên quan hoặc trong một điểm nhỏ bé.

Như các câu trả lời khác đã chỉ ra: Khái niệm ngoại lệ đã đưa ra một số ngôn ngữ không thuộc OOP. Không có gì trong khái niệm đó đòi hỏi một cái gì đó từ OOP.

Nhưng bất kỳ nếu không phải tất cả các ngôn ngữ OOP mất OOP đều yêu cầu ngoại lệ nghiêm trọng vì các phương pháp xử lý lỗi khác không thành công tại một điểm cụ thể: Hàm tạo.

Một trong những điểm của OOP là một đối tượng sẽ đóng gói và quản lý trạng thái bên trong của nó hoàn toàn và nhất quán. Điều này cũng có nghĩa là trong OOP thuần túy, bạn cần một khái niệm để tạo một đối tượng mới với trạng thái nhất quán "nguyên tử" - mọi thứ từ cấp phát bộ nhớ (nếu được yêu cầu) đến khởi tạo đến trạng thái có ý nghĩa (nghĩa là không có bộ nhớ đơn giản là không đủ) được thực hiện trong một biểu thức. Do đó, một constructor được yêu cầu:

Foo myFoo = Foo("foo", "bar", 42);

Nhưng điều này có nghĩa là hàm tạo cũng có thể bị lỗi do một số lỗi. Làm cách nào để truyền thông tin lỗi ra khỏi hàm tạo mà không có ngoại lệ?

  • Trả về giá trị? Thất bại vì trong một số ngôn ngữ chỉ newcó thể trả về nullnhưng không có bất kỳ thông tin đầy ý nghĩa nào. Trong các ngôn ngữ khác (ví dụ C ++) myFookhông phải là một con trỏ. Bạn không thể kiểm tra nó chống lại null. Ngoài ra, bạn không thể hỏi myFoovề lỗi - nó không được khởi tạo và do đó "không tồn tại" trong suy nghĩ OOP.

  • Cờ lỗi toàn cầu? Quá nhiều về trạng thái đóng gói và sau đó một số biến toàn cầu? Chuyển đến h ... ;-)

  • Một hỗn hợp? Không có cách nào tốt hơn.

  • ?

Vì vậy, các ngoại lệ là một khái niệm cơ bản hơn OOP nhưng OOP xây dựng theo chúng theo cách tự nhiên.


3
theo như tôi có thể nói, từ duy nhất trong "câu trả lời" này giải quyết câu hỏi thực tế được hỏi là "không". Phần còn lại có vẻ là về trường hợp ngoại lệ trong OOP - với tất cả sự tôn trọng với tôi đây đọc ở đâu đó giữa mơ hồ liên quanhoàn toàn không thích hợp - một lần nữa, trong bối cảnh của câu hỏi hỏi
một loại muôi

@gnat: TO cũng nói rằng anh ta không biết về nguồn gốc của các ngoại lệ. Do đó một chút lý do tại sao các trường hợp ngoại lệ ở khắp mọi nơi trên đất OO dường như là ổn đối với tôi. YMMV
AH

1
@AH Tôi phải đồng ý với gnat, ngoài dòng mở đầu, nó thực sự không giải quyết được câu hỏi. Phản hồi của bạn với gnat là "nói rằng anh ta không biết về nguồn gốc của các ngoại lệ" nhưng bạn thực sự không đưa ra một nguồn gốc của các ngoại lệ, chỉ là một số cách sử dụng ngoại lệ ngẫu nhiên trong quá trình khởi tạo đối tượng.

Các bạn, nghiêm túc chứ? -1? Hầu hết các câu trả lời khác cũng không đúng 100%. +1 từ tôi để bù đắp. Câu trả lời này cho lời khuyên nền tảng tốt trong một thế giới của các thiết kế lớp bị hỏng. (Sửa đổi: Nên tránh các nhà xây dựng nhiều bước)
Jo So

44

Có phải OOP chỉ liên quan?

Không. Ngoại lệ và OOP không liên quan.

Xử lý ngoại lệ là một cơ chế để xử lý lỗi. Một ngoại lệ được xử lý bằng cách lưu trạng thái thực thi hiện tại ở một nơi được xác định trước và chuyển đổi thực thi sang một chương trình con cụ thể được gọi là xử lý ngoại lệ.

So sánh C ( không thực sự là ngôn ngữ OOP , có thể bằng cách nào đó mô phỏng các ngoại lệ trong C ) và C ++ (OOP, hỗ trợ các ngoại lệ), không có gì ngăn cản ủy ban tiêu chuẩn của C thêm xử lý ngoại lệ vào C, nó vẫn sẽ không biến C thành ngôn ngữ OOP.


2
Bạn thậm chí có thể lập luận rằng đã có một số loại ngoại lệ được hỗ trợ trong HĐH thông thường. Hãy để chương trình của bạn gặp sự cố ("ngoại lệ" chưa được phát hiện) và với kết xuất lõi và trình gỡ lỗi, bạn thậm chí có được dấu vết ngăn xếp.
bhaak

12
Ngay cả MS BASIC từ những năm đầu thập niên 80 cũng có cách xử lý ngoại lệ:ON ERROR GOTO xxxx
jwernerny

1
@bhaak Anh ấy cũng có thể nói về việc kết xuất bộ nhớ trong Windows
JohnL

11
@jwernerny Xử lý lỗi? Chắc chắn rồi. Nhưng không ai gọi đó là xử lý ngoại lệ. Trong thực tế, nó thường trái ngược với xử lý ngoại lệ (có cấu trúc).
Konrad Rudolph

1
@jwernerny không chắc tôi làm theo; xử lý ngoại lệ như tôi đã hiểu đó là một cách rất cụ thể để xử lý lỗi. Khi tôi nghe ngoại lệ, tôi luôn nghĩ về try catchcấu trúc.
Andy

12

Một ngoại lệ là, chỉ đơn giản là, một tình huống đặc biệt cần sự chú ý và thường là sự thay đổi trong dòng chảy của việc thực hiện chương trình. Theo định nghĩa đó, các trường hợp ngoại lệ và xử lý ngoại lệ không giới hạn ở hướng đối tượng và các lỗi chương trình đơn giản có thể được coi là một dạng ngoại lệ.

Các ngôn ngữ hướng đối tượng thường có một lớp ngoại lệ riêng và tùy thuộc vào ngữ cảnh, từ "ngoại lệ" thực sự có thể ám chỉ lớp gốc đó thay vì khái niệm chung. Xử lý ngoại lệ hướng đối tượng, như hầu hết các hướng đối tượng, đường cú pháp và có thể dễ dàng được mô phỏng trong các ngôn ngữ không định hướng đối tượng. Đây là một ví dụ C, từ wikibook Lập trình C :

#include <stdio.h>
#include <setjmp.h>

jmp_buf test1;

void tryjump()
{
    longjmp(test1, 3);
}

int main (void)
{
    if (setjmp(test1)==0) {
        printf ("setjmp() returned 0.");
        tryjump();
    } else {
        printf ("setjmp returned from a longjmp function call.");
    }
}

6
Nó không chỉ đơn thuần là cú pháp đường. Việc tạo lại một ngăn xếp đầy đủ ngăn chặn và xử lý bắt theo kiểu là khó khăn với setjmp. Ngoài ra, việc tổng hợp đặc biệt các trường hợp ngoại lệ dẫn đến những lợi thế không thể bắt chước bằng setjmp.
edA-qa mort-ora-y

3
Tôi ghét các ngoại lệ mô tả là tình huống đặc biệt. Tôi muốn nói rằng các ngoại lệ nên được tạo (ném) khi không thể giải quyết tình huống lỗi với bối cảnh hiện tại vì không có đủ thông tin trong ngữ cảnh hiện tại để sửa lỗi chính xác.
Martin York

+1 cho setjmp.h
gnat

9

Câu trả lời là KHÔNG.

Một ví dụ điển hình cho ngôn ngữ không phải OO có ngoại lệ là ADA.


4
Hừm, tại sao ADA không phải là ngôn ngữ OO? Cấp, ADA83 thiếu đa hình nhưng nó vẫn có thể được coi là dựa trên đối tượng. Cũng kể từ ADA95, ngôn ngữ hoàn toàn hướng đối tượng.
yannis

Theo như tôi biết, việc xử lý ngoại lệ cũ hơn ADA83, do đó, bản thân ADA không phải là OO với xử lý ngoại lệ.
Uwe Plonus

2
@YannisRizos: Ada83 có các gói và gói chung nhưng không phải đối tượng. Họ đã được giới thiệu với Ada95.
mouviciel

2
@Yannis - Các đối tượng không có đa hình giống như lập trình có cấu trúc mà không có các khối lồng nhau. Đa hình là một trong những đặc điểm xác định của OOP. Ngay cả trong Ada95, các loại hỗ trợ liên kết thời gian chạy được gọi là "loại được gắn thẻ" thay vì "lớp", mặc dù tất nhiên đó chỉ là chính tả. Ada 83 có các bản ghi biến thể và nhiều loại khác nhau, nhưng không có loại nào trong số đó cung cấp các tính năng dành riêng cho OOP. Ada 83 là mô-đun và cấu trúc, nhưng nó không hướng đối tượng.
Steve314

3
@Yannis - về cơ bản, một số người trong cộng đồng Ada (như một số người ủng hộ hầu hết các ngôn ngữ) không thể chấp nhận rằng một tính năng có thể tốt, nhưng không được triển khai bằng ngôn ngữ yêu thích của họ và sẽ tạo ra mọi lý do để tin vào điều khác. Tuy nhiên, thậm chí không phải là một ngôn ngữ tốt cần có tất cả các tính năng ngôn ngữ tốt có thể (mặc dù thật dễ tin các nhà thiết kế Ada đã nghĩ như vậy). Tôi không thực sự tin tưởng vào cách tiếp cận tối giản trong thiết kế ngôn ngữ, nhưng ngôn ngữ tối đa cũng không hoàn hảo.
Steve314

7

Một số câu trả lời rất tốt ở đây rồi. Các ví dụ khác cho các ngôn ngữ lập trình không OOP có ngoại lệ:

  • Oracle PL / SQL

  • Visual Basic cổ điển (V6 trở xuống, "On Error Goto" là IMHO một hình thức xử lý ngoại lệ)

.


Ít nhất là các phiên bản QuickBASIC sau này trên DOS (trước Visual Basic; QB 4.5 là 1988 theo Wikipedia, VB 1.0 1991) đã xử lý lỗi bằng ON ERROR GOTOcú pháp. Ngay cả QuickBASIC cũng có một vài khái niệm tương tự OO (tôi nghĩ QB 4.5 thậm chí còn hỗ trợ một số loại) nhưng bạn khó có thể gọi BASIC chủ yếu là truyền thống hướng ngôn ngữ phù hợp. [Wikipedia ]
một CVn

5

Ý tưởng cơ bản đằng sau các ngoại lệ là dọn sạch luồng chương trình để lập trình viên có thể đi theo con đường thực thi "bình thường" dễ dàng hơn. Hãy xem xét một trường hợp đơn giản để mở tệp trong C. Ngay sau khi thử mở tệp, lập trình viên cần kiểm tra phản hồi từ lệnh gọi fopen () và quyết định xem cuộc gọi có thành công hay không. Nếu cuộc gọi không thành công, thì lập trình viên phải trả lời thích hợp. Cuộc gọi tiếp theo trong đường dẫn thực thi "bình thường", có lẽ là một cuộc gọi tới fread () hoặc fwrite (), sẽ xuất hiện sau khi các điều kiện lỗi hoặc lỗi đã được xử lý. Đó có thể là trên màn hình tiếp theo.

Với một ngôn ngữ cung cấp ngoại lệ, lệnh gọi fopen () tương đương có thể được theo dõi ngay lập tức bởi fread () hoặc fwrite (). Không có xử lý lỗi nào đang ẩn "bước tiếp theo" của đường dẫn thực thi "bình thường". Lập trình viên có thể thấy nhiều đường dẫn bình thường hơn trên một màn hình và do đó có thể theo dõi quá trình thực thi dễ dàng hơn. Việc xử lý lỗi được chuyển sang một phần khác của chương trình.

Bản thân các ngoại lệ không phải là một khái niệm OOP, nhưng chúng thường được thực hiện bằng cách sử dụng các khái niệm OOP giúp chúng thuận tiện và mạnh mẽ hơn. Ví dụ, các ngoại lệ có thể được xác định với hệ thống phân cấp thừa kế. Sử dụng ví dụ nổi tiếng của chúng tôi về việc mở và đọc hoặc viết một tệp, mỗi cuộc gọi đó có thể tạo ra nhiều ngoại lệ khác nhau - FileClosesException, DeviceFullException, NoSuchFileException, Insu enoughFilePermissionsException, v.v. kế thừa từ GenericException.

Nếu lập trình viên đang thực hiện một triển khai nhanh và bẩn để kiểm tra một khái niệm, anh ta có thể hầu như bỏ qua việc xử lý ngoại lệ và chỉ thực hiện một trình xử lý duy nhất cho GenericException. Trình xử lý đó sẽ xử lý GenericException và bất kỳ ngoại lệ nào kế thừa từ GenericException. Nếu anh ta muốn xử lý bất kỳ ngoại lệ nào liên quan đến tệp theo cùng một cách, anh ta có thể viết một trình xử lý cho FileException. Điều đó sẽ được gọi cho FileExceptions và bất kỳ trường hợp ngoại lệ nào kế thừa từ FileException. Nếu anh ta muốn viết một chương trình sẽ phản ứng khác nhau với nhiều điều kiện lỗi khác nhau, anh ta có thể viết một trình xử lý cụ thể cho từng ngoại lệ cụ thể.


3

Những người khác đã trả lời đúng "Không" với các ví dụ về ngôn ngữ. Tôi nghĩ rằng tôi có thể mở rộng bằng cách thêm một ví dụ về cách thêm ngoại lệ vào ngôn ngữ mà không bao giờ liên quan đến OOP.

Tôi sẽ làm điều này trong trường hợp DSKL (Ngôn ngữ hạt nhân tuần tự khai báo) của OZ , một ngôn ngữ rất phù hợp cho các công cụ hàn lâm như thế này. DSKL (hoặc DKL) có thể được nhìn thấy ở đây (kết quả tìm kiếm ngẫu nhiên), phần Tuyên bố và Giá trị. Định nghĩa chính xác không quan trọng, ngoài việc đây là một ngôn ngữ rất đơn giản, không có các biến có thể sửa đổi (chúng được khai báo và ràng buộc sau này) và không có OOP nào được tích hợp.

OOP thậm chí không thể được thêm vào như một sự trừu tượng hóa ngôn ngữ cho ngôn ngữ hạt nhân này. Bằng cách thêm tên duy nhất vào ngôn ngữ kernel (NewName) và sử dụng phạm vi cục bộ, đóng gói có thể đạt được. Hoặc bằng cách thêm một trạng thái có thể thay đổi vào ngôn ngữ kernel (NewCell) và sử dụng OOP phù hợp với phạm vi cục bộ với đóng gói có thể đạt được. Nhưng nó không thể đạt được chỉ với ngôn ngữ kernel được chỉ định.

Nếu sau đó chúng ta thêm ngoại lệ vào ngôn ngữ kernel, chúng ta sẽ có một ngôn ngữ không có hỗ trợ OOP nhưng có ngoại lệ. Hãy để tôi chỉ cho bạn cách:

Xác định một máy trừu tượng với một ngăn xếp và lưu trữ, chúng ta có thể định nghĩa mỗi câu lệnh trong ngôn ngữ của chúng ta nên làm gì ( ngữ nghĩa của câu lệnh). Chẳng hạn, skiptrong ngăn xếp không làm gì cả, A = 3trong ngăn xếp sẽ liên kết (/ thống nhất) A với (/ với) 3.

Chúng tôi bắt đầu bằng cách thêm cú pháp về cách xác định ngoại lệ của chúng tôi. Chúng tôi làm điều này bằng cách thêm hai mệnh đề khác vào <statement>trong DKL.

<statement>  ::== ... (old stuff)
                 | try <statement> catch <id> then <statement> end
                 | raise <id> end

Dưới đây là thử / bắt đã biết và một cách để tăng / ném ngoại lệ.

Chúng tôi xác định ngữ nghĩa của chúng bằng cách chúng hoạt động trên máy trừu tượng:

Hãy thử
Tuyên bố ngữ nghĩa là: (try <statement1> catch <id> then <statement2> end)
Làm:

  1. Nhấn vào ngăn xếp các tuyên bố ngữ nghĩa (catch <id> then <statement2> end)
  2. Nhấn vào ngăn xếp các tuyên bố ngữ nghĩa (<statement1>)

Lưu ý rằng câu lệnh 1 sẽ ở trên cùng của ngăn xếp và đã thử thực hiện trước.

Nâng cao
Tuyên bố ngữ nghĩa là: (raise <id> end)
Do:

  1. Nếu không có gì nữa trên ngăn xếp, hãy dừng lại và báo cáo một ngoại lệ chưa được lưu.
  2. Khác, bật tuyên bố ngữ nghĩa đầu tiên từ ngăn xếp. Nếu đó không phải là một tuyên bố bắt, hãy đến bước 1.
  3. Chúng tôi đã bắt được, trên hình thức (catch <id> then <statement> end)
    Đẩy (<statement>)lên ngăn xếp.

Bắt
Nếu chúng ta thấy một câu lệnh bắt trong khi thực thi bình thường, điều này có nghĩa là bất cứ điều gì bên trong được thực thi mà không đưa ra ngoại lệ lên đến mức này. Vì vậy, chúng tôi chỉ bật catchcác ngăn xếp và không làm gì cả.

QED, chúng tôi có một ngôn ngữ có ngoại lệ và không có khả năng OOP.

Tôi đã loại bỏ phần môi trường khỏi máy trừu tượng để làm cho nó đơn giản hơn.


1

Không.

IIRC, ngoại lệ xuất hiện trước các ngôn ngữ OO đầu tiên. AFAIK, các trường hợp ngoại lệ được hỗ trợ đầu tiên bởi các triển khai LISP sớm. Các ngôn ngữ có cấu trúc sớm (ví dụ ALGOL) và các ngôn ngữ OO sớm (ví dụ SIMULA) không hỗ trợ các ngoại lệ.


ALGON 68, tất nhiên, có ngoại lệ ("sự kiện"), nhưng nó cũng có mọi thứ khác. PL / Tôi cũng có chúng ("điều kiện ON"), và có tài liệu từ năm 1969 mô tả việc sử dụng chúng.
Ross Patterson
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.