ทำไมภาษาต้องใช้วงเล็บในการแสดงออกเมื่อใช้กับ“ ถ้า” และ“ ในขณะที่”


67

ภาษาเช่น C, Java และ C ++ ทั้งหมดต้องวงเล็บรอบการแสดงออกทั้งเมื่อนำมาใช้ในการให้if, หรือwhileswitch

if (true) {
    // Do something
}

ตรงข้ามกับ

if true {
    // Do something
}

นี่ดูแปลกสำหรับฉันเพราะวงเล็บซ้ำซ้อน ในตัวอย่างtrueนี้เป็นการแสดงออกเพียงอย่างเดียวของมันเอง วงเล็บไม่เปลี่ยนความหมายในทางใดทางหนึ่งที่ฉันรู้ ทำไมไวยากรณ์แปลก ๆ นี้จึงมีอยู่และทำไมมันจึงเป็นเรื่องธรรมดา? มีประโยชน์ไหมที่ฉันไม่ทราบ?


20
ปาสกาลไม่จำเป็นต้องใช้วงเล็บ (เพราะมันต้องมีTHEN)
JimmyB

30
Python, Ruby ทำไม่ได้
smci

31
ฉันเชื่อว่า C ใช้วงเล็บเพราะวงเล็บปีกกาเป็นทางเลือกสำหรับเนื้อความเดี่ยว หรือบางทีวิธีที่ดีกว่าที่จะกล่าวคือวงเล็บปีกกาไม่ได้เป็นส่วนหนึ่งของifคำสั่งพวกเขาเพียงสร้างคำสั่งผสม
Fred Larson

7
ไปน่าสนใจต้องใช้วงเล็บปีกกา แต่ไม่ใช่วงเล็บ
Kos

25
คำถามนี้ค่อนข้างจะซ้ำซากจำเจ ทำไมท่อระบายน้ำแบบกลมจึงครอบคลุมทุกรอบ? ทำไมพี่น้องทุกคนเป็นผู้ชาย? ทำไมทุกภาษาที่มีความต้องการ paren จำเป็นต้องมี parens ครอบคลุมท่อระบายน้ำกลมรอบโดยนิยาม; พี่น้องเป็นชายโดยนิยาม; ภาษาที่ต้องการ parens ต้องการ parens ตามคำจำกัดความ
Eric Lippert

คำตอบ:


155

จะต้องมีวิธีการบอกที่สิ้นสุดเงื่อนไขและสาขาเริ่ม มีหลายวิธีในการทำเช่นนั้น

ในบางภาษาไม่มีเงื่อนไขใดๆ เช่นใน Smalltalk, Self, Newspeak, Io, Ioke, Seph และ Fancy การแตกสาขาแบบมีเงื่อนไขนั้นใช้วิธีการปกติเหมือนกับวิธีอื่น ๆ วิธีการนี้จะถูกนำไปใช้กับวัตถุบูลีนและถูกเรียกบนบูลีน ด้วยวิธีนี้เงื่อนไขเป็นเพียงตัวรับวิธีและกิ่งทั้งสองนั้นเป็นสองข้อโต้แย้งเช่นใน Smalltalk:

aBooleanExpression ifTrue: [23] ifFalse: [42].

ในกรณีที่คุณคุ้นเคยกับ Java มากขึ้นสิ่งนี้จะเทียบเท่ากับสิ่งต่อไปนี้:

aBooleanExpression.ifThenElse(() -> 23, () -> 42);

ในตระกูลภาษา Lisp สถานการณ์คล้ายกัน: conditionals เป็นเพียงฟังก์ชันปกติ (จริง ๆ แล้วมาโคร) และอาร์กิวเมนต์แรกคือเงื่อนไขอาร์กิวเมนต์ที่สองและสามเป็นกิ่งดังนั้นจึงเป็นเพียงอาร์กิวเมนต์ของฟังก์ชันปกติและมี ไม่จำเป็นต้องมีสิ่งใดเป็นพิเศษในการกำหนดขอบเขต:

(if aBooleanExpression 23 42)

บางภาษาใช้คำหลักเป็นตัวคั่นเช่น Algol, Ada, BASIC, Pascal, Modula-2, Oberon, Oberon-2, Oberon ที่ใช้งานอยู่, Component Pascal, Zonnon, Modula-3:

IF aBooleanExpression THEN RETURN 23 ELSE RETURN 42;

ใน Ruby คุณสามารถใช้ทั้งคีย์เวิร์ดหรือตัวคั่นนิพจน์ (เซมิโคลอนหรือขึ้นบรรทัดใหม่):

if a_boolean_expression then 23 else 42 end

if a_boolean_expression; 23 else 42 end

# non-idiomatic, the minimum amount of whitespace required syntactically
if a_boolean_expression
23 else 42 end

# idiomatic, although only the first newline is required syntactically
if a_boolean_expression
  23
else
  42
end

Goต้องให้สาขาเป็นบล็อกและไม่อนุญาตให้มีการแสดงออกหรือคำสั่งซึ่งทำให้วงเล็บปีกกาบังคับ ดังนั้นไม่จำเป็นต้องใส่วงเล็บแม้ว่าคุณจะสามารถเพิ่มมันได้หากต้องการ Perl6 และ Rust มีความคล้ายคลึงกันในเรื่องนี้:

if aBooleanExpression { return 23 } else { return 42 }

บางภาษาใช้อักขระที่ไม่ใช่ตัวอักษรและตัวเลขอื่น ๆ เพื่อกำหนดเงื่อนไขเช่น Python:

if aBooleanExpression: return 23
else: return 42

บรรทัดล่างคือ: คุณต้องมีวิธีการบอกที่สิ้นสุดเงื่อนไขและสาขาเริ่ม มีหลายวิธีในการทำเช่นนั้นวงเล็บคือหนึ่งในนั้น


8
ภาพรวมที่ดีมาก
ปีเตอร์ - Reinstate Monica

2
แน่นอนในภาษาที่นิพจน์เปลือยไม่ได้เป็นคำสั่ง (เช่นบางอย่างเช่น BASIC ที่เก่ากว่าซึ่งค่าที่คำนวณต้องถูกกำหนดให้กับตัวแปรหรือส่งผ่านไปยังคำสั่งอื่น ๆ ) หรือที่ไม่มีตัวดำเนินการคำนำหน้าคุณควรจะสามารถ เพื่อระบุจุดสิ้นสุดของนิพจน์และเริ่มต้นของคำสั่งต่อไป แน่นอนฉันจะเห็นการจัดการชุดย่อยพื้นฐานโดยไม่มีตัวคั่นที่ท้ายคำสั่ง IF
Periata Breatta

4
นอกจากนี้เนื่องจาก C ได้รับการออกแบบในยุค 70 และการคำนวณมีราคาแพงการเพิ่มวงเล็บเล็กน้อยอาจทำให้ parser ง่ายต่อการเขียน
Machado

4
Re: เสียงกระเพื่อม: "อันที่จริงมาโคร" ในทางปฏิบัติหากเป็นรูปแบบพิเศษใน Scheme และ CL (เพียงเพื่อความสมบูรณ์)
coredump

1
@Lushushenko: และเช่นใน MISC ซึ่งเป็นสันหลังยาวโดยค่าเริ่มต้นรูปแบบตามเงื่อนไขทั้งหมดเป็นเพียงฟังก์ชั่นปกติไม่ใช่มาโครหรือรูปแบบพิเศษ (แน่นอน AFAIR, MISC มีรูปแบบพิเศษเป็นศูนย์หรือไม่?)
Jörg W Mittag

70

วงเล็บไม่จำเป็นถ้าคุณใช้วงเล็บปีกกา

if true ++ x;

ตัวอย่างเช่นไม่มีความชัดเจน


28
@RobertHarvey - วงเล็บเป็นภาษาที่ฉันรู้ แน่นอน C และเครือญาติ สหกรณ์จะถามว่าทำไมพวกเขาจะต้อง - และมันเป็นเพราะภาษาที่จะกลายเป็นที่คลุมเครืออย่างอื่น
Telastyn

25
เพิ่งออกจากส่วนบนของหัวฉันไม่จำเป็นต้องใช้วงเล็บifใน: พื้นฐานแอสเซมบลี python bash / zsh tcl แบทช์ brainfuck หรือรหัสเครื่อง การขาดเครื่องหมายวงเล็บจะทำให้เกิดifความกำกวมหากภาษานั้นได้รับการออกแบบให้พึ่งพาได้
candied_orange

12
อิ่มประหลาดใจที่ไม่มีใครกล่าวถึงมากที่สุดตรรกะและสามารถอ่านได้รุ่น - ในปาสคาล (Incl. Delphi) if Condition then ...มันเป็น
Ulrich Gerhardt

18
Go เป็นตัวอย่างที่ดีในการทำสิ่งตรงกันข้าม มันทำให้วงเล็บปีกกา{}ภาคบังคับและดังนั้นจึงไม่จำเป็นต้องมี parens รอบการแสดงออก ไม่เพียง แต่ไม่จำเป็นต้องใช้ parens เท่านั้น แต่หากฉันจำการเพิ่ม parens ได้อย่างถูกต้องจะทำให้เกิดข้อผิดพลาดในการคอมไพล์ - พวกมันถูกห้าม
slebetman

10
@Eiko ให้ฉันใช้ถ้อยคำใหม่ ตัวอย่างในคำตอบนั้นไม่ชัดเจนsyntacticallyแม้ว่ามันจะไม่มีความหมายชัดเจน (ตามที่คุณระบุ) แต่เนื่องจากขั้นตอนการแยกวิเคราะห์เกิดขึ้นก่อนการวิเคราะห์ความหมายตัวแยกวิเคราะห์จะพบความคลุมเครือ - และจะต้องทำการเดาที่ไม่รู้จริงหรือล้มเหลว หาก (ด้วยเหตุผลใด ๆ ) โปรแกรมแยกวิเคราะห์เลือกที่จะไม่ล้มเหลวตัววิเคราะห์ความหมายจะทำงานกับต้นไม้ผลลัพธ์ไม่ว่าจะเป็นอะไรก็ตาม ฉันไม่ได้เห็นคอมไพเลอร์ที่ซึ่งตัววิเคราะห์ความหมายยินดีที่จะให้ parser ทำการแยกย่อยทรีย่อยและสร้างทางเลือกที่แตกต่างกันที่โครงสร้างที่ไม่ชัดเจนของ syntactically
Theodoros Chatzigiannakis

21

วงเล็บในifคำสั่งไม่มีความหมายเหมือนกับวงเล็บที่ใช้ภายในนิพจน์ทางคณิตศาสตร์ เครื่องหมายวงเล็บในนิพจน์ทางคณิตศาสตร์ใช้เพื่อจัดกลุ่มนิพจน์เข้าด้วยกัน วงเล็บในifคำสั่งถูกใช้เพื่อคั่นนิพจน์บูลีน นั่นคือเพื่อแยกความแตกต่างของนิพจน์บูลีนจากifคำสั่งที่เหลือ

ในifคำสั่งวงเล็บไม่ทำการจัดกลุ่มฟังก์ชั่น (แม้ว่าภายในifคำสั่งคุณยังสามารถใช้วงเล็บเพื่อจัดกลุ่มนิพจน์ทางคณิตศาสตร์จากนั้นชุดวงเล็บด้านนอกจะทำหน้าที่กำหนดขอบเขตนิพจน์บูลีนทั้งหมด) ทำให้พวกเขาต้องการคอมไพเลอร์ง่ายขึ้นเนื่องจากคอมไพเลอร์สามารถพึ่งพาวงเล็บเหล่านั้นอยู่เสมอ


ฉันไม่เห็นว่าคอมไพเลอร์ลดความซับซ้อนได้อย่างไร กฎ `ถ้า '(' แสดงออก ')' statement` IF primary_expression statementไม่มีง่ายกว่า ขอให้สังเกตว่าหลังมีความชัดเจนเท่าเทียมกัน
user58697

@ user58697: ไม่เฉพาะอันหลังเท่านั้นที่มีความกำกวมซึ่งตัวดำเนินการ postfix บนprimary_expressionไม่สามารถแยกความแตกต่างจากตัวดำเนินการ prefix บนคำสั่ง expression ได้ ในการคัดลอกคำตอบ Telastyn if true ++ x;ของ นอกจากนี้หากมีคำสั่งที่ว่างเปล่าif a & f;อาจเป็นคำสั่งที่ว่างเปล่าและไบนารี&ภายในเงื่อนไขหรือเป็นเอกเทศ&ที่จุดเริ่มต้นของคำสั่ง แต่เมื่อจับคู่วงเล็บมีการจับคู่หนึ่งรายการสำหรับการเปิด (
MSalters

@MSalters ตัวดำเนินการ postfix ไม่แยกเป็นหลัก นิพจน์หลักคือหนึ่งIDENTIFIER, CONSTANT, และSTRING_LITERAL '(' expression ')'
user58697

@ user58697: ดูเหมือนว่าคุณจะมีภาษาเฉพาะ และดูเหมือนว่าจะมีกฎที่ไม่จำเป็นต้องใช้วงเล็บในกรณีที่เงื่อนไขเป็น "IDENTIFIER, CONSTANT หรือ STRING_LITERAL" เท่านั้น ฉันไม่แน่ใจว่าจะทำให้สิ่งต่าง ๆ ง่ายขึ้น
MSalters

16

ดังที่คนอื่น ๆ ได้ชี้ไปแล้วบางส่วนนี่เป็นเพราะความจริงที่ว่านิพจน์นั้นเป็นประโยคที่ถูกต้องและในกรณีของบล็อกที่มีเพียงคำสั่งเดียวคุณก็สามารถใส่เครื่องหมายวงเล็บได้ ซึ่งหมายความว่าสิ่งต่อไปนี้ไม่ชัดเจน:

if true
    +x;

เพราะมันอาจตีความได้ว่า:

if (true + x) {}

แทน:

if (true) {+x;}

จำนวนภาษา (เช่น Python) อนุญาตให้คุณหลีกเลี่ยงวงเล็บ แต่ยังมีเครื่องหมายสิ้นสุดเงื่อนไข:

ถ้าเป็น True : + x

อย่างไรก็ตามคุณมีสิทธิ์ที่เราสามารถกำหนดภาษาที่ไม่จำเป็นต้องใช้วงเล็บ: ภาษาที่นิพจน์ไม่ใช่คำสั่งที่ถูกต้องจะไม่มีปัญหานี้

น่าเสียดายที่สิ่งนี้หมายความว่า:

 ++x;
 functionCall(1,2,3);

จะไม่เป็นข้อความที่ถูกต้องดังนั้นคุณต้องแนะนำไวยากรณ์แปลก ๆ เพื่อให้สามารถดำเนินการดังกล่าวได้โดยไม่ต้องสร้างนิพจน์ วิธีง่ายๆในการทำเช่นนี้คือเพียงเติมนิพจน์โดยเครื่องหมายเช่น[statement]:

[statement] ++x;
[statement] functionCall(1,2,3);

ตอนนี้ความคลุมเครือหายไปตั้งแต่คุณต้องเขียน:

if true
    [statement] ++x;

แต่อย่างที่คุณเห็นฉันไม่เห็นว่าภาษาดังกล่าวแพร่หลายไปทั่วเนื่องจากวางวงเล็บไว้รอบ ๆif-condition (หรือ:ท้ายที่สุด) จะดีกว่ามากแล้วให้วางเครื่องหมายดังกล่าวสำหรับคำสั่งการแสดงออกทุกคำ


หมายเหตุ : การใช้[statement]เครื่องหมายเป็นเพียงไวยากรณ์ที่ง่ายที่สุดที่ฉันคิดได้ อย่างไรก็ตามคุณสามารถมีสองไวยากรณ์ที่แตกต่างกันอย่างสมบูรณ์สำหรับการแสดงออกและงบที่ไม่มีความกำกวมระหว่างพวกเขาซึ่งจะไม่ต้องมีเครื่องหมายดังกล่าว ปัญหาคือ: ภาษาจะแปลกมากเนื่องจากการทำสิ่งเดียวกันในการแสดงออกหรือคำสั่งที่คุณต้องใช้ไวยากรณ์ที่แตกต่างอย่างสิ้นเชิง

สิ่งหนึ่งที่อยู่ในใจที่จะมีสองไวยากรณ์ที่แยกจากกันได้โดยไม่ต้องดังกล่าวเป็นเครื่องหมายอย่างชัดเจนจะเป็นตัวอย่างเช่น: งบบังคับให้ใช้สัญลักษณ์ Unicode (ดังนั้นแทนที่จะforคุณต้องการใช้รูปแบบ Unicode บางส่วนของตัวอักษรf, oและr) ในขณะที่การแสดงออกจะเป็น ASCII เท่านั้น


2
ภาษาที่มีอยู่จริงที่ใช้เช่นเครื่องหมายคำสั่งการแสดงออก: ถ้าคุณต้องการที่จะประเมินผลการแสดงออกสำหรับผลข้างเคียงของมันคุณจะต้องชัดเจนด้านความคุ้มค่าในสะเดาdiscard อย่างไรก็ตามนั่นเป็นเพียงเพื่อความปลอดภัยของประเภทไม่ใช่เพื่อเหตุผลทางวากยสัมพันธ์
amon

@amon ดีฉันไม่รู้เกี่ยวกับเรื่องนั้น อย่างไรก็ตามอย่างที่ฉันบอกว่าเครื่องหมายไม่จำเป็นจริงๆมันเป็นเพียงวิธีง่ายๆในการบรรลุความแตกต่างนั้นโดยไม่ต้องประดิษฐ์ซินแท็กซ์ที่ไม่ใช้งานง่าย
Bakuriu

1
@amon - ตัวแปรพื้นฐานหลายรายการมีการแยกระหว่างนิพจน์และข้อความสั่งอย่างเข้มงวด นิพจน์ได้รับอนุญาตเฉพาะในสถานที่ที่จะใช้ค่าจริง (เช่นการกำหนดตัวแปรข้อความสั่งเช่น PRINT ที่ดำเนินการและอื่น ๆ ) ขั้นตอนที่ไม่ได้ใช้ในการคำนวณค่าจะถูกเรียกใช้โดยคำหลัก (โดยทั่วไปคือ "CALL" แม้ว่าจะมีตัวแปรอย่างน้อยหนึ่งตัวที่ฉันรู้จักใช้ "PROC") ซึ่งเป็นคำนำหน้าชื่อของพวกเขา และอื่น ๆ BASIC มักจะคั่นจุดสิ้นสุดของนิพจน์ในคำสั่ง IF ด้วย "THEN" แต่ฉันไม่เห็นเหตุผลทางเทคนิคใด ๆ ที่ไม่สามารถทิ้งข้อกำหนดได้
Periata Breatta

1
มีภาษาที่ได้รับความนิยมอย่างมากในยุค 80 ที่มีบล็อกโดยไม่มี parens, braces, colons หรือ marker อื่นและยอมรับการแสดงออกเป็นคำพูดทุกที่และบางประโยคก็ทำหน้าที่เหมือนนิพจน์ มันแย่ลงมีตัวประมวลผลก่อนเป็นใบ้ก่อนคอมไพเลอร์ ( ?ตัวอย่างซิมโบลในความเป็นจริงคือฟังก์ชั่นหลังจาก PP) ;ไม่มี แน่นอนว่ามันจำเป็นต้องมีเครื่องหมายสำหรับเส้นต่อเนื่อง แต่สิ่งนี้เป็นสิ่งที่ทำให้หมดกำลังใจ harbour.github.io/doc/clc53.html#if-cmd คอมไพเลอร์นั้นเร็วและง่าย (สร้างด้วย Bison / Flex)
Maniero

@bigown พวกเขาประสบความสำเร็จที่โดยใช้ไวยากรณ์ที่แยกต่างหากสำหรับตรรกะเงื่อนไขดังนั้นโดยทั่วไปเงื่อนไขสำหรับif, whileECC มี จำกัด เมื่อเทียบกับการแสดงออกทั่วไปที่ใช้ในภาษาอื่น ๆ แน่นอน: ถ้าคุณมีหมวดหมู่เกี่ยวกับการสร้างประโยคมากกว่าสองประเภท (เช่นคำสั่ง, การแสดงออก, การแสดงออกทางตรรกะ, การทำกาแฟ, ... ) คุณสามารถแลกเปลี่ยนอิสระได้
บากูริว

10

เป็นเรื่องปกติที่ภาษาตระกูล C จะต้องใช้วงเล็บเหล่านี้ แต่ไม่ใช่ภาษาสากล

หนึ่งของการเปลี่ยนแปลงที่เห็นได้ชัดเจนขึ้นประโยค Perl 6 คือว่าพวกเขาปรับเปลี่ยนไวยากรณ์เพื่อที่คุณจะได้ไม่ต้องให้วงเล็บรอบif, forและเงื่อนไขงบที่คล้ายกัน ดังนั้นสิ่งเช่นนี้ใช้ได้อย่างสมบูรณ์ใน Perl 6:

if $x == 4 {
    ...
}

อย่างที่เป็น

while $queue.pop {
    ...
}

อย่างไรก็ตามเนื่องจากเป็นเพียงนิพจน์คุณสามารถใส่วงเล็บไว้รอบ ๆ ได้หากคุณต้องการในกรณีนี้พวกเขาเป็นเพียงการจัดกลุ่มธรรมดาแทนที่จะเป็นส่วนที่จำเป็นของไวยากรณ์ตามที่อยู่ใน C, C #, Java เป็นต้น

Rust มีไวยากรณ์คล้ายกับ Perl 6 ในแผนกนี้:

if x == 4 {
    ...
}

สำหรับฉันแล้วดูเหมือนว่าคุณลักษณะของภาษา C ที่ได้แรงบันดาลใจที่ทันสมัยกว่าคือการมองสิ่งต่าง ๆ เช่นนี้และสงสัยเกี่ยวกับการลบออก


ในขณะที่คำตอบของคุณให้ข้อมูลเชิงลึกเกี่ยวกับภาษาอื่น ๆ ก็ไม่ตอบ "ทำไมไวยากรณ์ผิดปกตินี้จึงมีอยู่และทำไมมันจึงเป็นเรื่องธรรมดา?

คุณค่อนข้างถูกต้อง ฉันต้องการเพิ่มบริบทให้กับคำถามซึ่งไม่ใช่เรื่องง่ายที่จะทำในแพลตฟอร์มนี้ ในที่สุดฉันก็เดาได้ว่าถ้าฉันให้คำตอบกับคำถามว่า "เพราะเพราะไม่มีเหตุผลทางเทคนิคไวยากรณ์ไม่สามารถรองรับได้หากไม่มี" แต่นั่นไม่ใช่คำตอบที่มีประโยชน์มาก
Matthew Walton

ใน Perl 5 มีทั้งคู่ สำหรับปกติ ifโครงสร้างหรือห่วงกับบล็อก parens จะต้องเช่นในหรือif ( $x == 4 ) { ... } foreach my $foo ( @bar ) { ... }เมื่อสัญกรณ์ postfix จะใช้ parens เป็นตัวเลือกเช่นเดียวกับในหรือreturn unless $foo; ++$x while s/foo/bar/g;
simbabque

6

มีแง่มุมหนึ่งที่ฉันประหลาดใจที่ไม่มีคำตอบใด ๆ ที่ปรากฏขึ้น

C และอนุพันธ์ C หลายรายการและ look-alikes มีลักษณะเฉพาะที่ค่าของการกำหนดเป็นค่าที่กำหนด ผลที่ตามมาคือสิ่งนี้คือการมอบหมายสามารถใช้ที่คาดว่าค่า

สิ่งนี้ช่วยให้คุณเขียนสิ่งต่าง ๆ เช่น

if (x = getValue() == 42) { ... }

หรือ

if (x == y = 47) { ... }

หรือ

unsigned int n = 0 /* given m == SOME_VALUE */;
while (n < m && *p1++ = *p2++) { n++; }

(ซึ่งได้รับการปฏิบัติโดยปริยายwhile (n < m && *p1++ = *p2++ != 0) { n++; }เพราะ C ถือว่าไม่เป็นศูนย์เป็นจริงโดยบังเอิญฉันคิดว่ามันเป็นเรื่องเกี่ยวกับ strncpy () ในไลบรารีมาตรฐาน C)

หรือแม้กระทั่ง

if (x = 17);

และมันก็ใช้ได้จริง การรวมกันที่ถูกต้องของ syntactically ไม่จำเป็นต้องมีประโยชน์ (และคอมไพเลอร์สมัยใหม่เตือนเฉพาะเกี่ยวกับการมอบหมายภายใน conditionals เพราะมันเป็นข้อผิดพลาดทั่วไป) แต่บางส่วนมันมีประโยชน์จริง

การแยกประโยคดังกล่าวน่าจะยากกว่านี้หากไม่มีวิธีที่ชัดเจนในการพิจารณาว่าการแสดงออกของเงื่อนไขเริ่มต้นและสิ้นสุดที่ใด

วงเล็บถูกใช้แล้วเพื่อกำหนดชื่อฟังก์ชันจากอาร์กิวเมนต์ของฟังก์ชันดังนั้นฉันคิดว่าพวกเขาดูเหมือนเป็นทางเลือกที่เป็นธรรมชาติเช่นกันในการกำหนดคำหลักจากอาร์กิวเมนต์ของคำหลัก

แน่นอนว่าสามารถกำหนดไวยากรณ์ทางเลือกให้ทำสิ่งเดียวกันได้ แต่การทำเช่นนั้นจะเพิ่มความซับซ้อนโดยเฉพาะใน parser ซึ่งจะต้องจัดการกับไวยากรณ์สองชุดที่แตกต่างกันเพื่อสิ่งเดียวกัน ย้อนกลับเมื่อ C ได้รับการออกแบบพลังในการคำนวณ (ทั้งในแง่ของความสามารถในการ จำกัด จำนวนหน่วยความจำในการทำงานและความจุในการจัดเก็บ) นั้น จำกัด มาก สิ่งใดก็ตามที่ลดความซับซ้อนเพียงเล็กน้อยหรือไม่มีค่าใช้จ่ายในการอ่านก็เป็นการเปลี่ยนแปลงที่น่ายินดี

การใช้วงเล็บอาจดูคร่ำครึเล็กน้อยในวันนี้ แต่ไม่ใช่ว่าคนที่มีความคุ้นเคยกับภาษาจะทำให้การอ่านง่ายกว่าเมื่อเปรียบเทียบกับไวยากรณ์อื่น ๆ ที่สามารถแสดงสิ่งเดียวกัน


5

เหตุผลส่วนใหญ่เป็นประวัติศาสตร์

ในขณะที่คอมไพเลอร์ C ตัวแรกเขียนคอมพิวเตอร์มีหน่วยความจำ RAM, cpu และคอมไพเลอร์ที่เขียน“ ด้วยมือ” ที่มีเครื่องมือน้อยมากที่จะช่วยผู้เขียนคอมไพเลอร์ ดังนั้นกฎที่ซับซ้อนจึงมีค่าใช้จ่ายสูงในการนำไปใช้ในคอมไพเลอร์ C ++, C #, Java และอื่น ๆ ทั้งหมดได้รับการออกแบบมาเพื่อให้ง่ายสำหรับโปรแกรมเมอร์ C ในการเรียนรู้ดังนั้นจึงไม่มีการเปลี่ยนแปลง "ไม่จำเป็น"

ในเงื่อนไข 'c like' languages ​​( if, while, etc) ไม่จำเป็นต้องใช้blockรหัสนอกคุณสามารถใช้คำสั่งง่ายๆ

if (a == d) doIt()

หรือคุณสามารถรวมคำสั่งเข้าด้วยกันcompound statementโดยการวางไว้ใน{}

เราชอบคอมไพเลอร์เพื่อค้นหาข้อผิดพลาดที่เราทำและให้เป็นข้อผิดพลาดที่เราสามารถเข้าใจได้


3

ทั้ง Java และ C ++ ได้รับการพัฒนาหลังจาก C กลายเป็นภาษาการเขียนโปรแกรมที่ได้รับความนิยมอย่างมาก สิ่งหนึ่งที่ควรพิจารณาในการออกแบบของแต่ละภาษาเหล่านั้นคือมันจะดึงดูดโปรแกรมเมอร์ C และแสวงหาโปรแกรมเมอร์ที่จะใช้ภาษาใหม่ (ฉันเป็นหนึ่งในโปรแกรมเมอร์ C ที่พวกเขาประสบความสำเร็จ) C ++ นอกจากนี้ยังได้รับการออกแบบให้เปลี่ยนได้ (เกือบ) ด้วยรหัส C เพื่อสนับสนุนเป้าหมายเหล่านี้ทั้ง C ++ และ Java นำมาใช้มากไวยากรณ์ของ C รวมทั้งวงเล็บรอบเงื่อนไขของif, whileและswitchงบ

ดังนั้นเหตุผลที่ภาษาทั้งหมดเหล่านี้ต้องใช้วงเล็บล้อมรอบเงื่อนไขของข้อความเหล่านั้นเป็นเพราะ C ทำและคำถามนี้เป็นเพียงเหตุผลว่าทำไม C ต้องการวงเล็บเหล่านั้น

ต้นกำเนิดของภาษา C ที่อธิบายไว้ใน บทความนี้โดยเดนนิสริตชี่หนึ่งในนักเขียนที่สำคัญของการพัฒนา (บางคนอาจจะบอกว่าผู้เขียนหลักของการพัฒนา) ดังที่ได้กล่าวไว้ในบทความนั้น C ได้รับการพัฒนามาตั้งแต่ต้นปี 1970 ในฐานะภาษาการเขียนโปรแกรมระบบสำหรับคอมพิวเตอร์ที่มีพื้นที่ จำกัด อย่างมากในหน่วยความจำหลัก มันต้องการที่จะมีภาษาที่ระดับสูงกว่าภาษาแอสเซมบลี แต่เนื่องจากทรัพยากรที่มีอยู่ในการทำงานด้วยความสะดวกในการแยกวิเคราะห์ภาษาก็มีความสำคัญเช่นกัน การขอวงเล็บจะทำให้มันง่ายต่อการระบุรหัสเงื่อนไข

หนึ่งอาจอนุมานได้ว่าความสามารถในการเขียนโปรแกรมโดยใช้ตัวอักษรน้อยลงถือว่าเป็นข้อได้เปรียบและวงเล็บสองอันใช้พื้นที่น้อยกว่าคำหลักTHENที่ใช้ใน FORTRAN และภาษาระดับสูงอื่น ๆ ในเวลานั้น ในความเป็นจริงตั้งแต่วงเล็บยังสามารถแทนที่ช่องว่างเป็นตัวคั่นสัญลักษณ์เป็นสี่ตัวอักษรทั้งสั้นกว่าif(a==b)IF a==b THEN

ไม่ว่าในกรณีใดก็ตามความสมดุลบางอย่างจะต้องเกิดขึ้นระหว่างความง่ายของมนุษย์ที่จะสามารถอ่านเขียนและทำความเข้าใจกับโปรแกรมที่เขียนใน C ความเรียบง่ายที่คอมไพเลอร์สามารถวิเคราะห์และคอมไพล์โปรแกรมที่เขียนด้วย C และจำนวนกิโลไบต์ (!) จะต้องมีทั้งสำหรับแหล่งโปรแกรมและคอมไพเลอร์เอง และวงเล็บล้อมรอบเงื่อนไขของif, whileและswitch ข้อความก็คือวิธีที่ผู้คนเลือกที่จะสมดุลในการออกแบบของ C.

ดังที่เห็นได้จากคำตอบอื่น ๆ เมื่อคุณนำสถานการณ์เฉพาะที่ได้รับการพัฒนา C มาใช้รูปแบบทางเลือกทุกประเภทของไวยากรณ์ได้ถูกนำมาใช้สำหรับเงื่อนไขของภาษาโปรแกรมต่างๆ ดังนั้นวงเล็บจึงลงมาสู่การตัดสินใจออกแบบที่ทำโดยคนไม่กี่คนภายใต้ข้อ จำกัด บางอย่างในช่วงเวลาหนึ่งในประวัติศาสตร์


ฉันไม่แน่ใจว่ามันยุติธรรมที่จะบอกว่า C ++ ได้รับการออกแบบในลักษณะที่เป็น "เพื่อแสวงหาโปรแกรมเมอร์ผู้ใช้ภาษาใหม่" จำC กับคลาสได้หรือไม่
CVn

@ MichaelKjörlingเป็นที่ยอมรับกันว่านักพัฒนา Java มีความชัดเจนมากขึ้นเกี่ยวกับ "การแสวงหา" แต่โปรดทราบว่าบทความที่เชื่อมโยงอ้างถึงเป็นหนึ่งในเหตุผลที่ Stroustrup เลือกที่จะเริ่มต้นด้วย C เป็นพื้นฐานของภาษาของเขาว่า C ถูกใช้อย่างกว้างขวาง วิธีหนึ่งที่ที่ให้แรงจูงใจที่จะอยู่ใกล้กับ C เป็นเพราะรหัสที่มีอยู่อาจจะดัดแปลงได้ง่าย (ที่ผมกล่าวแล้ว) - แต่ยังมีอยู่โคดได้อย่างง่ายดายสามารถปรับตัวเข้ากับ
David K

@ MichaelKjörlingฉันคิดว่าถ้อยคำต้นฉบับของคำตอบของฉันบอกว่า "การแสวงหา" เป็นปัจจัยสำคัญในการออกแบบภาษามากกว่าที่เป็นจริง ฉันได้แก้ไขคำตอบเพื่อพยายามชี้แจงว่ามันเป็นเพียงสิ่งเดียวที่รวมอยู่ในการออกแบบภาษา
David K

3

หลายคนที่นี่มีเหตุผลว่าถ้าไม่มีวงเล็บไวยากรณ์จะคลุมเครือและพูดอย่างเงียบ ๆ ว่าสิ่งนี้จะไม่ดีอย่างใดอย่างหนึ่งหรือแม้กระทั่งสถานการณ์ที่เป็นไปไม่ได้

ในความเป็นจริงภาษามีวิธีมากมายในการจัดการกับความคลุมเครือ ความสำคัญของผู้ประกอบการเป็นเพียงตัวอย่างเดียวของหัวข้อนี้

ไม่ความกำกวมไม่ใช่เหตุผลของวงเล็บ ฉันเดาว่าหนึ่งสามารถสร้างรุ่นของ C ซึ่งไม่จำเป็นต้องใช้วงเล็บรอบเงื่อนไข (จึงทำให้พวกเขาเป็นตัวเลือก) และยังคงสร้างรหัสที่ถูกต้องในทุกกรณี ตัวอย่างของif a ++ b;การตีความอาจเทียบเท่าif (a) ++b;หรือหรือif (a++) b;อะไรก็ตามที่ดูเหมาะสมกว่า

คำถามที่ว่าทำไมเดนนิสริชชี่เลือกที่จะทำให้ () บังคับ (และทำให้การสร้าง meme นี้สำหรับภาษาที่ได้รับมามากมาย) ค่อนข้างจะเป็นภาษาศาสตร์ ฉันเดาว่าความคิดในการระบุอย่างชัดเจนว่าเงื่อนไขเป็นการแสดงออกแทนที่จะเป็นคำสั่งเป็นพ่อของความคิด

และในความเป็นจริง C ได้รับการออกแบบให้เป็นแบบแยกวิเคราะห์โดยใช้ตัวแยกวิเคราะห์แบบ one-pass การใช้ไวยากรณ์พร้อมวงเล็บบังคับรอบเงื่อนไขสนับสนุนแง่มุมนี้


ฉันเห็นคำตอบของฉัน โปรดอธิบายในความคิดเห็นในสิ่งที่คุณไม่ชอบ บางทีฉันสามารถปรับปรุงได้
Alfe

0

ifไม่ต้องใช้วงเล็บในเงื่อนไขใน Fortran, Cobol, PL / 1, Algol, Algo-68, Pascal, Modula, XPL, PL / M, MPL, ... หรือภาษาอื่น ๆ ที่มีthenคำหลัก thenทำหน้าที่ในการกำหนดเขตจากต่อไปนี้conditionstatement

วงเล็บปิดใน C ฯลฯ ทำหน้าที่เป็นthenและอันที่เปิดอย่างเป็นทางการนั้นซ้ำซ้อน

ข้อสังเกตข้างต้นนำไปใช้กับภาษาที่แยกวิเคราะห์แบบดั้งเดิม


Fortran ไม่จำเป็นต้องมีวงเล็บในทุกรุ่นของ IF รวมทั้งโครงสร้างหนึ่ง
Netch
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.