สำหรับภาษาร่วมสมัยมันเป็นแค่น้ำตาลประโยค ในทางที่ไม่เชื่อเรื่องภาษาอย่างสมบูรณ์มันเป็นมากกว่านั้น
ก่อนหน้านี้คำตอบนี้ระบุไว้เพียงว่ามันเป็นมากกว่าน้ำตาลประโยค แต่ถ้าคุณจะเห็นในความคิดเห็น Falco ยกประเด็นว่ามีชิ้นส่วนของปริศนาที่ภาษาร่วมสมัยดูเหมือนจะหายไป; พวกเขาไม่ได้ผสมวิธีการมากไปกับการกำหนดแบบไดนามิกของฟังก์ชันที่จะเรียกใช้ในขั้นตอนเดียวกัน จะมีการชี้แจงในภายหลัง
นี่คือเหตุผลที่มันควรจะมากขึ้น
พิจารณาภาษาที่รองรับทั้งวิธีการโอเวอร์โหลดและตัวแปรที่ไม่ได้พิมพ์ คุณสามารถมีต้นแบบวิธีการดังต่อไปนี้:
bool someFunction(int arg);
bool someFunction(string arg);
ในบางภาษาคุณอาจถูกลาออกเพื่อทราบเวลารวบรวมซึ่งจะมีการเรียกหนึ่งในรหัสเหล่านี้ แต่ในบางภาษาจะไม่มีการพิมพ์ตัวแปรทั้งหมด (หรือพวกเขากำลังพิมพ์โดยปริยายObject
หรืออะไรก็ตาม) ดังนั้นลองนึกภาพการสร้างพจนานุกรมที่คีย์คีย์จับคู่กับค่าประเภทต่าง ๆ :
dict roomNumber; // some hotels use numbers, some use letters, and some use
// alphanumerical strings. In some languages, built-in dictionary
// types automatically use untyped values for their keys to map to,
// so it makes more sense then to allow for both ints and strings in
// your code.
ทีนี้ถ้าคุณต้องการสมัครsomeFunction
กับหมายเลขห้องเหล่านั้นล่ะ คุณเรียกสิ่งนี้ว่า:
someFunction(roomNumber[someSortOfKey]);
ถูกsomeFunction(int)
เรียกหรือถูกsomeFunction(string)
เรียก? ที่นี่คุณจะเห็นตัวอย่างหนึ่งซึ่งสิ่งเหล่านี้ไม่ใช่วิธีการตั้งฉากแบบสมบูรณ์โดยเฉพาะในภาษาระดับสูงกว่า ภาษาต้องคิดออก - ในระหว่างรันไทม์ - ซึ่งหนึ่งในสิ่งเหล่านี้ที่จะเรียกดังนั้นจึงยังคงต้องพิจารณาว่าสิ่งเหล่านี้เป็นอย่างน้อยวิธีเดียวกัน
ทำไมไม่ใช้แค่แม่แบบ? ทำไมไม่ใช้เพียงอาร์กิวเมนต์ที่ไม่มีการพิมพ์?
ความยืดหยุ่นและการควบคุมที่ละเอียดยิ่งขึ้น บางครั้งการใช้เทมเพลต / อาร์กิวเมนต์ที่ไม่มีการพิมพ์เป็นวิธีที่ดีกว่า แต่บางครั้งก็ใช้ไม่ได้
คุณต้องคิดเกี่ยวกับกรณีที่ตัวอย่างเช่นคุณอาจมีสองวิธีลายเซ็นที่แต่ละคนใช้int
และstring
เป็นข้อโต้แย้ง แต่ที่สั่งซื้อจะแตกต่างกันในแต่ละลายเซ็น คุณอาจมีเหตุผลที่ดีในการทำเช่นนี้เนื่องจากการใช้งานของลายเซ็นแต่ละครั้งอาจทำสิ่งเดียวกัน แต่ส่วนใหญ่แตกต่างกันเล็กน้อย ตัวอย่างเช่นการบันทึกอาจแตกต่างกัน หรือแม้ว่าพวกเขาจะทำสิ่งเดียวกันคุณสามารถรวบรวมข้อมูลบางอย่างโดยอัตโนมัติจากลำดับที่มีการระบุอาร์กิวเมนต์ ในทางเทคนิคคุณสามารถใช้คำสั่ง pseudo-switch เพื่อกำหนดประเภทของอาร์กิวเมนต์แต่ละตัวที่ส่งผ่านเข้ามา
ดังนั้นนี่คือตัวอย่างการฝึกการเขียนโปรแกรมที่ไม่ดีต่อไปหรือไม่?
bool stringIsTrue(int arg)
{
if (arg.toString() == "0")
{
return false;
}
else
{
return true;
}
}
bool stringIsTrue(Object arg)
{
if (arg.toString() == "0")
{
return false;
}
else
{
return true;
}
}
bool stringIsTrue(string arg)
{
if (arg == "0")
{
return false;
}
else
{
return true;
}
}
ใช่โดยและมีขนาดใหญ่ ในตัวอย่างนี้มันสามารถป้องกันไม่ให้ใครบางคนพยายามที่จะใช้สิ่งนี้กับประเภทดั้งเดิมบางอย่างและกลับมาทำงานที่ไม่คาดคิด (ซึ่งอาจเป็นสิ่งที่ดี); แต่ลองสมมุติว่าฉันย่อรหัสข้างต้นและที่จริงแล้วคุณมีโอเวอร์โหลดสำหรับประเภทดั้งเดิมทั้งหมดรวมถึงObject
s ด้วย จากนั้นโค้ดถัดไปนี้จะเหมาะสมกว่าจริงๆ:
bool stringIsTrue(untyped arg)
{
if (arg.toString() == "0")
{
return false;
}
else
{
return true;
}
}
แต่ถ้าคุณต้องการใช้สิ่งนี้กับint
s และstring
s เท่านั้นและถ้าคุณต้องการให้มันกลับมาจริงโดยใช้เงื่อนไขที่ง่ายกว่าหรือซับซ้อนกว่านั้น จากนั้นคุณมีเหตุผลที่ดีในการใช้งานมากไป:
bool appearsToBeFirstFloor(int arg)
{
if (arg.digitAt(0) == 1)
{
return true;
}
else
{
return false;
}
}
bool appearsToBeFirstFloor(string arg)
{
string firstCharacter = arg.characterAt(0);
if (firstCharacter.isDigit())
{
return appearsToBeFirstFloor(int(firstCharacter));
}
else if (firstCharacter.toUpper() == "A")
{
return true;
}
else
{
return false;
}
}
แต่เฮ้ทำไมไม่ให้ชื่อเหล่านั้นฟังก์ชั่นสองชื่อต่างกันล่ะ? คุณยังคงมีการควบคุมอย่างละเอียดเหมือนเดิมใช่ไหม?
เนื่องจากตามที่ระบุไว้ก่อนหน้าโรงแรมบางแห่งใช้ตัวเลขบางแห่งใช้ตัวอักษรและบางแห่งใช้ตัวเลขและตัวอักษรผสมกัน:
appearsToBeFirstFloor(roomNumber[someSortOfKey]);
// will treat ints and strings differently, without you having to write extra code
// every single spot where the function is being called
นี่ยังไม่ใช่รหัสที่แน่นอนเหมือนกันที่ฉันจะใช้ในชีวิตจริง แต่ควรแสดงให้เห็นถึงจุดที่ฉันกำลังทำอยู่
แต่ ...นี่คือเหตุผลว่าทำไมมันจึงไม่ได้เป็นเพียงแค่น้ำตาลในภาษาร่วมสมัย
ฟัลโกยกประเด็นในการแสดงความคิดเห็นว่าภาษาปัจจุบันโดยทั่วไปไม่ได้ผสมวิธีมากไปและการเลือกฟังก์ชั่นแบบไดนามิกในขั้นตอนเดียวกัน วิธีก่อนหน้านี้ฉันเข้าใจบางภาษาในการทำงานคือคุณสามารถโอเวอร์โหลดappearsToBeFirstFloor
ในตัวอย่างด้านบนและจากนั้นภาษาจะพิจารณาว่ารันไทม์เวอร์ชันใดของฟังก์ชันที่จะเรียกใช้ขึ้นอยู่กับค่ารันไทม์ของตัวแปรที่ไม่ได้พิมพ์ ความสับสนนี้เกิดจากการทำงานกับภาษา ECMA บางส่วนเช่น ActionScript 3.0 ซึ่งคุณสามารถสุ่มฟังก์ชั่นที่เรียกใช้กับรหัสบรรทัดที่รันไทม์ได้อย่างง่ายดาย
อย่างที่คุณอาจทราบแล้วว่า ActionScript 3 ไม่รองรับวิธีการโอเวอร์โหลด สำหรับ VB.NET คุณสามารถประกาศและตั้งค่าตัวแปรได้โดยไม่ต้องกำหนดชนิดอย่างชัดเจน แต่เมื่อคุณพยายามส่งตัวแปรเหล่านี้เป็นอาร์กิวเมนต์ไปยังวิธีการโอเวอร์โหลดมันยังคงไม่ต้องการอ่านค่ารันไทม์เพื่อกำหนดวิธีการโทร มันต้องการหาวิธีที่มีอาร์กิวเมนต์ชนิดObject
หรือไม่มีหรือแทนที่จะเป็นอย่างอื่นแทน ดังนั้นint
เมื่อเทียบกับstring
ตัวอย่างข้างต้นจะไม่ทำงานในภาษาที่อย่างใดอย่างหนึ่ง C ++ มีปัญหาที่คล้ายกันเช่นเมื่อคุณใช้บางสิ่งบางอย่างเช่นตัวชี้โมฆะหรือกลไกอื่น ๆ เช่นนั้นมันยังคงต้องการให้คุณแยกแยะประเภทในเวลารวบรวม
ดังนั้นตามที่หัวข้อแรกบอกว่า ...
สำหรับภาษาร่วมสมัยมันเป็นแค่น้ำตาลประโยค ในทางที่ไม่เชื่อเรื่องภาษาอย่างสมบูรณ์มันเป็นมากกว่านั้น การใช้วิธีการมากเกินไปมีประโยชน์และเกี่ยวข้องเช่นในตัวอย่างข้างต้นอาจเป็นคุณสมบัติที่ดีในการเพิ่มภาษาที่มีอยู่ (ตามที่ได้รับการร้องขออย่างกว้างขวางสำหรับ AS3) หรืออาจเป็นหนึ่งในเสาหลักที่แตกต่างกันสำหรับ การสร้างภาษาเชิงกระบวนงาน / เชิงวัตถุใหม่