คำตอบ:
ความแตกต่างระหว่างภาษาที่พิมพ์อย่างยิ่งและภาษาที่พิมพ์แบบคงที่คืออะไร?
ภาษาที่พิมพ์แบบสแตติกมีระบบประเภทที่ตรวจสอบ ณ เวลารวบรวมโดยการนำไปใช้ (คอมไพเลอร์หรือล่าม) การตรวจสอบประเภทปฏิเสธโปรแกรมบางโปรแกรมและโปรแกรมที่ผ่านการตรวจสอบมักมาพร้อมกับการรับประกันบางส่วน ตัวอย่างคอมไพเลอร์รับประกันว่าจะไม่ใช้คำสั่งเลขคณิตจำนวนเต็มกับตัวเลขทศนิยม
ไม่มีข้อตกลงที่แท้จริงในสิ่งที่ "พิมพ์อย่างรุนแรง" หมายถึงแม้ว่าคำจำกัดความที่ใช้กันอย่างแพร่หลายในวรรณคดีมืออาชีพคือในภาษา "พิมพ์อย่างยิ่ง" มันเป็นไปไม่ได้ที่โปรแกรมเมอร์จะหลีกเลี่ยงข้อ จำกัด ที่กำหนดโดยระบบประเภท . คำนี้มักใช้เพื่ออธิบายภาษาที่พิมพ์แบบคงที่
ตรงกันข้ามของการพิมพ์แบบคงที่คือ "พิมพ์แบบไดนามิก" ซึ่งหมายความว่า
ตัวอย่างเช่นLuaซึ่งเป็นภาษาที่พิมพ์แบบไดนามิกมีประเภทสตริงประเภทตัวเลขและประเภทบูลีนท่ามกลางคนอื่น ๆ ใน Lua ค่าเป็นของตรงชนิดหนึ่ง แต่ตอนนี้ไม่จำเป็นต้องสำหรับภาษาพิมพ์แบบไดนามิกทั้งหมด ใน Lua อนุญาตให้ทำการต่อสองสายได้ แต่ไม่อนุญาตให้ต่อสายและ Boolean
ตรงกันข้ามของ "การพิมพ์ที่รุนแรง" คือ "การพิมพ์ที่ไม่รัดกุม" ซึ่งหมายความว่าคุณสามารถแก้ไขระบบพิมพ์ได้ C เป็นตัวพิมพ์ที่มีความอ่อนแออย่างฉาวโฉ่เนื่องจากตัวชี้ชนิดใด ๆ สามารถแปลงเป็นตัวชี้ชนิดอื่น ๆ ได้ง่ายๆโดยการร่าย ปาสคาลตั้งใจที่จะพิมพ์อย่างยิ่ง แต่การกำกับดูแลในการออกแบบ (บันทึกตัวแปรแปรผัน) นำช่องโหว่เข้าสู่ระบบประเภทดังนั้นเทคนิคในการพิมพ์อย่างอ่อน ตัวอย่างของภาษาที่พิมพ์อย่างแท้จริง ได้แก่ CLU, ML มาตรฐานและ Haskell ในความเป็นจริงแล้ว ML มาตรฐานมีการแก้ไขหลายครั้งเพื่อลบช่องโหว่ในระบบพิมพ์ที่ค้นพบหลังจากใช้ภาษาอย่างกว้างขวาง
โดยรวมแล้วดูเหมือนจะไม่มีประโยชน์ที่จะพูดถึง "แข็งแรง" และ "อ่อนแอ" ไม่ว่าระบบประเภทนั้นจะมีช่องโหว่สำคัญน้อยกว่าจำนวนที่แน่นอนและลักษณะของช่องโหว่นั้นเป็นไปได้หรือไม่ว่าพวกเขาจะเกิดขึ้นได้อย่างไรในทางปฏิบัติและสิ่งที่เป็นผลมาจากการเจาะช่องโหว่นั้น ในทางปฏิบัติควรหลีกเลี่ยงคำว่า "แข็งแรง" และ "อ่อนแอ" โดยสิ้นเชิงเพราะ
มือสมัครเล่นมักจะแชทด้วย "คงที่" และ "ไดนามิก"
เห็นได้ชัดว่า "การพิมพ์ที่อ่อนแอ" ถูกใช้โดยบุคคลบางคนเพื่อพูดคุยเกี่ยวกับความชุกญาติหรือไม่มีการแปลงโดยนัย
ผู้เชี่ยวชาญไม่สามารถเห็นด้วยกับสิ่งที่คำว่า
โดยรวมแล้วคุณไม่น่าจะแจ้งหรือให้ความกระจ่างแก่ผู้ชมของคุณ
ความจริงที่น่าเศร้าก็คือเมื่อมันมาถึงระบบการพิมพ์"แข็งแรง" และ "อ่อนแอ" ไม่ได้มีการตกลงกันอย่างกว้างขวางเกี่ยวกับความหมายทางเทคนิค หากคุณต้องการพูดคุยเกี่ยวกับความแข็งแกร่งสัมพัทธ์ของระบบประเภทมันจะดีกว่าเพื่อหารือเกี่ยวกับสิ่งที่รับประกันและไม่ได้ให้ ตัวอย่างเช่นคำถามที่ดีที่จะถามคือ: "คือทุกค่าของประเภทที่กำหนด (หรือคลาส) ที่รับประกันว่าจะถูกสร้างขึ้นโดยการเรียกหนึ่งในคอนสตรัคเตอร์ของประเภทนั้น" ใน C คำตอบคือไม่ ใน CLU, F # และ Haskell คือใช่ สำหรับ C ++ ฉันไม่แน่ใจ - ฉันอยากรู้
ในทางตรงกันข้ามการพิมพ์แบบสแตติกหมายถึงมีการตรวจสอบโปรแกรมก่อนที่จะดำเนินการและโปรแกรมอาจถูกปฏิเสธก่อนที่จะเริ่มต้น การพิมพ์แบบไดนามิกหมายถึงการตรวจสอบประเภทของค่าในระหว่างการดำเนินการและการพิมพ์ที่ไม่ดีอาจทำให้โปรแกรมหยุดชะงักหรือส่งสัญญาณข้อผิดพลาดในเวลาทำงาน เหตุผลหลักสำหรับการพิมพ์แบบคงที่คือการออกกฎโปรแกรมที่อาจมี "ข้อผิดพลาดประเภทแบบไดนามิก"
คนหนึ่งพูดถึงอีกคนหนึ่งหรือไม่?
ในระดับอวดรู้ไม่เพราะคำว่า "แข็งแรง" ไม่ได้มีความหมายอะไรเลย แต่ในทางปฏิบัติผู้คนมักทำหนึ่งในสองสิ่งต่อไปนี้:
พวกเขา (ไม่ถูกต้อง) ใช้ "แข็งแรง" และ "อ่อนแอ" เพื่อหมายถึง "คงที่" และ "ไดนามิก" ซึ่งในกรณีนี้พวกเขา (ไม่ถูกต้อง) ใช้ "พิมพ์อย่างรุนแรง" และ "พิมพ์แบบคงที่" สลับกันได้
พวกเขาใช้ "แข็งแรง" และ "อ่อนแอ" เพื่อเปรียบเทียบคุณสมบัติของระบบประเภทคงที่ มันเป็นเรื่องยากมากที่จะได้ยินใครบางคนพูดเกี่ยวกับระบบประเภทไดนามิกที่ "แข็งแรง" หรือ "อ่อนแอ" ยกเว้น FORTH ซึ่งไม่มีระบบการพิมพ์ใด ๆ จริง ๆ ฉันไม่สามารถนึกถึงภาษาที่พิมพ์แบบไดนามิกที่สามารถพิมพ์ระบบย่อยได้ เรียงลำดับตามคำจำกัดความการตรวจสอบเหล่านั้นจะถูกใส่เข้าไปในเอ็นจินการเรียกใช้และทุกการดำเนินการจะได้รับการตรวจสอบเพื่อความมีสติก่อนที่จะถูกประหารชีวิต
ไม่ว่าจะด้วยวิธีใดหากบุคคลเรียกภาษาที่ "พิมพ์อย่างรุนแรง" บุคคลนั้นมีแนวโน้มที่จะพูดถึงภาษาที่พิมพ์แบบคงที่
บ่อยครั้งที่ฉันเข้าใจผิด
การพิมพ์แบบคงที่คือที่ชนิดถูกผูกไว้กับตัวแปร ประเภทจะถูกตรวจสอบในเวลารวบรวม
พิมพ์แบบไดนามิกเป็นที่ที่คนประเภทที่ถูกผูกไว้กับความคุ้มค่า ประเภทจะถูกตรวจสอบในเวลาทำงาน
ดังนั้นใน Java เช่น:
String s = "abcd";
s
จะ "ตลอดไป" String
เป็น ในช่วงชีวิตของมันอาจชี้ไปที่String
s ที่แตกต่างกัน(เนื่องจากs
เป็นข้อมูลอ้างอิงใน Java) มันอาจจะมีnull
ค่า แต่มันจะไม่เคยอ้างถึงหรือInteger
List
นั่นคือการพิมพ์แบบคงที่
ใน PHP:
$s = "abcd"; // $s is a string
$s = 123; // $s is now an integer
$s = array(1, 2, 3); // $s is now an array
$s = new DOMDocument; // $s is an instance of the DOMDocument class
นั่นคือการพิมพ์แบบไดนามิก
(แก้ไขการแจ้งเตือน!)
การพิมพ์ที่แข็งแกร่งเป็นวลีที่ไม่มีความหมายที่ตกลงกันอย่างกว้างขวาง โปรแกรมเมอร์ส่วนใหญ่ที่ใช้คำนี้หมายถึงสิ่งอื่นนอกเหนือจากการพิมพ์แบบสแตติกใช้เพื่อบ่งบอกว่ามีระเบียบวินัยประเภทที่บังคับใช้โดยคอมไพเลอร์ ตัวอย่างเช่น CLU มีระบบชนิดที่แข็งแกร่งที่ไม่อนุญาตให้โค้ดไคลเอ็นต์สร้างค่าประเภทนามธรรมยกเว้นโดยใช้ตัวสร้างที่จัดเตรียมโดยชนิด C มีระบบชนิดที่ค่อนข้างแข็งแกร่ง แต่สามารถ "subverted" ถึงระดับหนึ่งได้เนื่องจากโปรแกรมสามารถส่งค่าประเภทตัวชี้หนึ่งไปยังค่าชนิดตัวชี้อื่นได้เสมอ ตัวอย่างเช่นใน C คุณสามารถนำค่าที่ส่งคืนมาmalloc()
และนำไปใช้อย่างสนุกสนานFILE*
และคอมไพเลอร์จะไม่พยายามหยุดคุณ - หรือแม้แต่เตือนคุณว่าคุณกำลังทำอะไรหลบ ๆ
(คำตอบดั้งเดิมพูดอะไรบางอย่างเกี่ยวกับค่า "ไม่เปลี่ยนชนิดในเวลาทำงาน" ฉันรู้จักนักออกแบบภาษาและนักเขียนคอมไพเลอร์จำนวนมาก ระบบซึ่งเป็นที่รู้จักกันในชื่อ "ปัญหาการอัพเดทที่แข็งแกร่ง")
การพิมพ์ที่อ่อนแอหมายความว่าคอมไพเลอร์ไม่บังคับใช้ discpline หรือบางทีการบังคับใช้อาจล้มล้างได้ง่าย
ต้นฉบับของคำตอบนี้พิมพ์ด้วยคำว่าอ่อนแอโดยใช้การแปลงโดยนัย (บางครั้งเรียกว่า "การส่งเสริมโดยนัย") ตัวอย่างเช่นใน Java:
String s = "abc" + 123; // "abc123";
นี่คือรหัสเป็นตัวอย่างของโปรโมชั่นโดยนัยนี้: 123 "abc"
จะถูกแปลงโดยปริยายสตริงก่อนที่จะถูกตัดแบ่งกับ สามารถโต้เถียงคอมไพเลอร์ Java เขียนรหัสนั้นใหม่เป็น:
String s = "abc" + new Integer(123).toString();
พิจารณาปัญหา "เริ่มต้นด้วย" PHP แบบคลาสสิก:
if (strpos('abcdef', 'abc') == false) {
// not found
}
ข้อผิดพลาดที่นี่คือการstrpos()
ส่งคืนดัชนีของการแข่งขันโดยมีค่าเป็น 0 0 จะถูกรวมเข้ากับบูลีนfalse
และทำให้เงื่อนไขเป็นจริง ทางออกคือการใช้===
แทน==
การหลีกเลี่ยงการแปลงโดยนัย
ตัวอย่างนี้แสดงให้เห็นว่าการผสมผสานการแปลงโดยนัยและการพิมพ์แบบไดนามิกสามารถทำให้โปรแกรมเมอร์หลงทางได้อย่างไร
เปรียบเทียบกับ Ruby:
val = "abc" + 123
ซึ่งเป็นข้อผิดพลาดรันไทม์เพราะใน Ruby วัตถุ 123 ไม่ได้ถูกแปลงโดยปริยายเพราะมันเกิดขึ้นเพื่อส่งผ่านไปยัง+
เมธอด ใน Ruby โปรแกรมเมอร์จะต้องทำการแปลงอย่างชัดเจน:
val = "abc" + 123.to_s
การเปรียบเทียบ PHP และ Ruby เป็นภาพประกอบที่ดีที่นี่ ทั้งสองเป็นภาษาที่พิมพ์แบบไดนามิก แต่ PHP มีการแปลงโดยนัยจำนวนมากและ Ruby (อาจแปลกใจถ้าคุณไม่คุ้นเคยกับมัน)
จุดนี่คือแกนคงที่ / ไดนามิกเป็นอิสระจากแกนที่แข็งแกร่ง / อ่อนแอ ผู้คนอาจสับสนในบางส่วนเนื่องจากการพิมพ์ที่รัดกุมและอ่อนแอไม่เพียง แต่นิยามที่ชัดเจนน้อยลงเท่านั้นยังไม่มีฉันทามติที่แท้จริงเกี่ยวกับความหมายที่แข็งแกร่งและอ่อนแอ ด้วยเหตุนี้การพิมพ์ที่แข็งแรง / อ่อนจึงมีเฉดสีเทามากกว่าดำหรือขาว
ดังนั้นเพื่อตอบคำถามของคุณ: อีกวิธีในการดูที่ส่วนใหญ่ถูกต้องคือการพูดแบบคงที่คือความปลอดภัยประเภทเวลารวบรวมและการพิมพ์ที่แข็งแกร่งคือความปลอดภัยประเภทรันไทม์
เหตุผลในการนี้คือตัวแปรในภาษาที่พิมพ์แบบคงที่มีประเภทที่ต้องประกาศและสามารถตรวจสอบได้ในเวลารวบรวม ภาษาที่พิมพ์อย่างรุนแรงมีค่าที่มีชนิดในขณะใช้งานและเป็นเรื่องยากสำหรับโปรแกรมเมอร์ที่จะล้มล้างระบบประเภทโดยไม่ต้องตรวจสอบแบบไดนามิก
แต่สิ่งสำคัญคือต้องเข้าใจว่าภาษาสามารถเป็นแบบคงที่ / เข้มแข็งแบบคงที่ / แบบอ่อนแอแบบไดนามิก / แบบไดนามิกหรือแบบไดนามิก / แบบอ่อน
"abc" + 123
เป็นข้อผิดพลาดรันไทม์ไม่ใช่ข้อผิดพลาดในการรวบรวมในทับทิม หากเป็นข้อผิดพลาดในการคอมไพล์ทับทิมจะถูกพิมพ์แบบคงที่
ทั้งคู่เป็นเสาที่แตกต่างกันสองแกน:
หมายถึงพิมพ์อย่างมาก , จะไม่ถูกแปลงโดยอัตโนมัติจากประเภทหนึ่งไปยังประเภทอื่น พิมพ์อ่อนอยู่ตรงข้าม: Perl สามารถใช้สตริงเช่น"123"
ในบริบทที่เป็นตัวเลขโดยการแปลงมันโดยอัตโนมัติใน 123
int ภาษาที่พิมพ์อย่างรุนแรงเช่น python จะไม่ทำเช่นนี้
พิมพ์แบบคงที่หมายถึงคอมไพเลอร์ตัวเลขประเภทของตัวแปรที่รวบรวมเวลา ภาษาที่พิมพ์แบบไดนามิกจะระบุประเภทของตัวแปรที่รันไทม์เท่านั้น
พิมพ์อย่างรุนแรงหมายความว่ามีข้อ จำกัด ระหว่างการแปลงระหว่างประเภท การพิมพ์แบบสแตติกหมายถึงประเภทนั้นไม่ได้เป็นแบบไดนามิกคุณไม่สามารถเปลี่ยนชนิดของตัวแปรได้เมื่อมันถูกสร้างขึ้น
การบังคับใช้ข้อมูลไม่จำเป็นต้องหมายถึงการพิมพ์ที่อ่อนแอเพราะบางครั้งน้ำตาลของวากยสัมพันธ์:
ตัวอย่างด้านบนของ Java ถูกพิมพ์อย่างอ่อนเนื่องจาก
String s = "abc" + 123;
ไม่ได้เป็นตัวอย่างที่พิมพ์ออกมาไม่ดีนักเพราะมันกำลังทำอยู่:
String s = "abc" + new Integer(123).toString()
การบังคับใช้ข้อมูลยังไม่ได้พิมพ์อย่างอ่อนหากคุณกำลังสร้างวัตถุใหม่ Java เป็นตัวอย่างที่ไม่ดีอย่างมากของการพิมพ์ที่ไม่รัดกุม เนื่องจากรันไทม์ของภาษามักจะรู้ว่าประเภทคืออะไร (ข้อยกเว้นอาจเป็นประเภทพื้นเมือง)
นี่คือสิ่งที่แตกต่างจาก C. C เป็นหนึ่งในตัวอย่างที่ดีที่สุดของการพิมพ์ที่อ่อนแอ รันไทม์ไม่มีความคิดถ้า 4 ไบต์เป็นจำนวนเต็ม struct ตัวชี้หรือ 4 ตัวอักษร
รันไทม์ของภาษากำหนดว่าจริง ๆ หรือไม่พิมพ์อ่อนอย่างนั้นมันเป็นเพียงความเห็น
แก้ไข: หลังจากคิดเพิ่มเติมนี้ไม่จำเป็นต้องเป็นจริงเพราะ runtime ไม่จำเป็นต้องมีชนิดทั้งหมด reified ในระบบ runtime เป็นระบบที่พิมพ์อย่างรุนแรง Haskell และ ML มีการวิเคราะห์แบบสแตติกที่สมบูรณ์ซึ่งพวกเขาสามารถได้ข้อมูลประเภท ommit จากรันไทม์
คำตอบได้รับไปแล้ว พยายามแยกแยะระหว่างแนวคิดที่แข็งแกร่งเทียบกับสัปดาห์และแนวคิดแบบคงที่เทียบกับแบบไดนามิก
พิมพ์อย่างมาก: จะไม่ถูกแปลงโดยอัตโนมัติจากประเภทหนึ่งเป็นประเภทอื่น
ใน Go หรือ Python เช่นภาษาที่พิมพ์อย่างยิ่ง "2" + 8 จะทำให้เกิดข้อผิดพลาดประเภทเนื่องจากไม่อนุญาตให้ใช้ "type coercion"
Weakly (loosely) Typed: จะถูกแปลงเป็นประเภทหนึ่งเป็นอีกประเภทโดยอัตโนมัติ: ภาษาที่พิมพ์อย่างอ่อนเช่น JavaScript หรือ Perl จะไม่เกิดข้อผิดพลาดและในกรณีนี้ JavaScript จะให้ผลลัพธ์ '28' และ perl จะส่งผลให้ 10
ตัวอย่าง Perl:
my $a = "2" + 8;
print $a,"\n";
บันทึกลงใน main.pl และเรียกใช้perl main.pl
แล้วคุณจะได้รับผลลัพธ์ 10
ในการเขียนโปรแกรมโปรแกรมเมอร์กำหนดการพิมพ์แบบคงที่และการพิมพ์แบบไดนามิกที่เกี่ยวข้องกับจุดที่ชนิดของตัวแปรจะถูกตรวจสอบ ภาษาที่พิมพ์แบบคงที่เป็นภาษาที่ใช้ในการตรวจสอบประเภทที่รวบรวมเวลาในขณะที่ภาษาที่พิมพ์แบบไดนามิกนั้นเป็นภาษาที่ใช้ในการตรวจสอบประเภทในเวลาทำงาน
นี่หมายถึงอะไร?
ในไปมันตรวจสอบพิมพ์ก่อนรันไทม์ (ตรวจสอบคงที่) ซึ่งหมายความว่ามันไม่เพียง แต่แปลและตรวจสอบรหัสที่กำลังดำเนินการ แต่มันจะสแกนรหัสทั้งหมดและข้อผิดพลาดประเภทจะถูกโยนทิ้งก่อนที่รหัสจะทำงาน ตัวอย่างเช่น,
package main
import "fmt"
func foo(a int) {
if (a > 0) {
fmt.Println("I am feeling lucky (maybe).")
} else {
fmt.Println("2" + 8)
}
}
func main() {
foo(2)
}
บันทึกไฟล์นี้ใน main.go และเรียกใช้คุณจะได้รับการรวบรวมข้อความล้มเหลวสำหรับเรื่องนี้
go run main.go
# command-line-arguments
./main.go:9:25: cannot convert "2" (type untyped string) to type int
./main.go:9:25: invalid operation: "2" + 8 (mismatched types string and int)
แต่กรณีนี้ใช้ไม่ได้กับ Python ตัวอย่างเช่นการบล็อกรหัสต่อไปนี้จะดำเนินการสำหรับการโทร foo (2) ครั้งแรกและจะล้มเหลวสำหรับการโทร foo (0) ครั้งที่สอง มันเป็นเพราะ Python ถูกพิมพ์แบบไดนามิกมันจะแปลและพิมพ์รหัสตรวจสอบที่มันทำงานอยู่เท่านั้น บล็อกอื่นจะไม่ดำเนินการกับ foo (2) ดังนั้น "2" + 8 จะไม่เคยดูแม้แต่และสำหรับ foo (0) การเรียกมันจะพยายามเรียกใช้บล็อกนั้นและล้มเหลว
def foo(a):
if a > 0:
print 'I am feeling lucky.'
else:
print "2" + 8
foo(2)
foo(0)
คุณจะเห็นผลลัพธ์ต่อไปนี้
python main.py
I am feeling lucky.
Traceback (most recent call last):
File "pyth.py", line 7, in <module>
foo(0)
File "pyth.py", line 5, in foo
print "2" + 8
TypeError: cannot concatenate 'str' and 'int' objects
หนึ่งไม่ได้หมายความถึงอื่น ๆ สำหรับภาษาที่จะพิมพ์แบบสแตติกหมายความว่าชนิดของตัวแปรทั้งหมดเป็นที่รู้จักหรืออนุมานได้ในเวลารวบรวม
อย่างยิ่งภาษาพิมพ์ไม่ยอมให้คุณใช้ประเภทหนึ่งเป็นอีก C เป็นภาษาที่พิมพ์อย่างอ่อนและเป็นตัวอย่างที่ดีของภาษาที่ไม่สามารถพิมพ์ได้ ใน C คุณสามารถส่งองค์ประกอบข้อมูลประเภทที่ไม่ถูกต้องและจะไม่บ่น ในภาษาที่พิมพ์อย่างรุนแรงคุณไม่สามารถ
การพิมพ์ที่รัดกุมอาจหมายความว่าตัวแปรมีประเภทที่กำหนดไว้อย่างดีและมีกฎที่เข้มงวดเกี่ยวกับการรวมตัวแปรประเภทต่าง ๆ ในนิพจน์ ตัวอย่างเช่นถ้า A เป็นจำนวนเต็มและ B เป็นทศนิยมดังนั้นกฎที่เข้มงวดเกี่ยวกับ A + B อาจเป็นได้ว่า A ถูกส่งไปที่ float และผลลัพธ์ที่ส่งกลับเป็น float ถ้า A เป็นจำนวนเต็มและ B เป็นสตริงกฎที่เข้มงวดอาจเป็นว่า A + B ไม่ถูกต้อง
การพิมพ์คงที่อาจหมายถึงประเภทที่กำหนดในเวลารวบรวม (หรือเทียบเท่าสำหรับภาษาที่ไม่ได้รวบรวม) และไม่สามารถเปลี่ยนแปลงได้ในระหว่างการดำเนินการโปรแกรม
โปรดทราบว่าการจำแนกประเภทเหล่านี้ไม่ได้เกิดขึ้นพร้อมกันโดยเฉพาะฉันคาดว่าพวกเขาจะเกิดขึ้นพร้อมกันบ่อยครั้ง ภาษาที่พิมพ์จำนวนมากยังมีการพิมพ์แบบคงที่
และโปรดทราบว่าเมื่อฉันใช้คำว่า 'อาจจะ' เป็นเพราะไม่มีคำจำกัดความที่ยอมรับในระดับสากลของคำเหล่านี้ อย่างที่คุณจะได้เห็นจากคำตอบแล้ว