Перейти до вмісту

Простір назв

Матеріал з Вікіпедії — вільної енциклопедії.

Про́стір назв[1][2][3][4], також про́стір іме́н[5][6][7] або іменни́й про́стір[джерело?] (англ. namespace) — концепція у програмуванні, призначена для розмежування різних множин ідентифікаторів і уникнення конфліктів між їхніми назвами.

Ідентифікатор, зосереджений у просторі імен, асоціюється з цим простором. Один і той самий ідентифікатор може бути незалежно визначений у декількох просторах. Значення, пов'язане з ідентифікатором, який знаходиться в одному просторі імен, може мати (чи не мати) таке ж саме значення, як і той самий ідентифікатор, визначений у іншому просторі. Мови з підтримкою просторів імен визначають правила, завдяки яким, можна визначити до якого простору імен належить ідентифікатор (тобто його значення).

Приклад: Андрій працює в компанії X, а ID. Він має ідентифікатор працівника, який дорівнює 123. Олег працює в компанії Y, а його ID так само дорівнює 123. Значення в обох єдине (з точки зору якоїсь системи обліку), завдяки чому Андрія та Олега можна розрізнити при співпадаючих ID, це характеризує їх приналежність до різних підприємств. Різниця компаній, у цьому випадку, являє собою систему різних просторів імен (одна компанія - один простір). Наявність двох працівників у компанії з однаковими ID створює значні проблеми при їх використанні, наприклад, по платіжному чеку, в якому буде вказано працівник з ID 123, буде досить важко визначити працівника, якому цей чек призначається.

У великих базах даних можуть існувати сотні та тисячі ідентифікаторів. Простори назв (або схожі структури) реалізують механізм для приховування локальних ідентифікаторів. Угрупування логічно пов'язаних ідентифікаторів, у відповідних просторах імен, створює модульну систему. Обмеження видимості змінних може також проводитися шляхом завдання класу її пам'яті .

Операційні системи, а також більшість серед сучасних мов програмування, забезпечують підтримку власної моделі просторів імен: використовують каталоги, (або папки) як модель простору імен. Це дозволяє існувати двом файлам з однаковим ім'ям (за умови, що вони знаходяться в різних каталогах). У деяких мовах програмування (наприклад, C ++, Python) ідентифікатори імен просторів самі асоціюються з необхідними просторами. У таких мовах простір імен може вкладатися один до одного, формуючи дерево просторів імен. Корінь такого дерева отримує назву глобального простору імен.

Використання у мовах

[ред. | ред. код]

Java-пакети втілюють ідею просторів імен. Увесь код, зосереджений усередині пакету, який не потребує явно заданого ім'я. Код з інших пакетів доступний при префіксному посиланню на ім'я пакету перед відповідним ідентифікатором, наприклад, клас String в пакеті java.lang може бути викликаний як java.lang. String (даний спосіб відомий як повне ім'я класу ). Як і в C ++, Java пропонує конструкцію, що робить необов'язковим вказівку ім'я пакета ( import ). У той самий час, деякі особливості (як, наприклад, відображення ) вимагають від програміста використання повного імені.

На відміну від C ++, простір імен у Java не є ієрархічно впорядкованим через синтаксис мови. Проте, пакети іменуються в ієрархічному стилі. Наприклад, усі пакети, які починаються з java , є частиною платформи Java - пакет java.lang, що містить базові класи мови, у той самий час у java.lang.reflect [Архівовано 31 січня 2019 у Wayback Machine.] містяться базові класи, специфічні для відображення (рефлексії).

У мові Java (так само, як і в Ада , C # та інших мовах) простори імен / пакети відображають семантичні категорії коду. Як приклад, у C # namespace System містить код, що реалізується системою (платформа . NET). Як саме визначаються ці категорії і наскільки глибока ієрархія - залежить від самої мови.

Функція і клас можуть бути визначені, як неявний простір імен, складно пов'язані з видимістю, доступністю і періодом життя об'єкта .

У мові C # існують простори імен, які вживаються аналогічно C ++.

В Python кожен ідентифікатор може знаходитись в локальному або глобальному просторі назв, або всередині певного об'єкта (модуля, або будь-якого іншого). Функція locals() повертає словник (асоціативний масив) з ідентифікаторами локального простору назв[8], globals() — глобального[9]. Функція dir() покаже список ідентифікаторів доступних з поточного фрейму, якщо викликана без параметрів, і список ідентифікаторів всередині об'єкта, якщо викликана з якимось об'єктом[10].

Змінна оголошена всередині іншої функції потрапляє в локальний простір назв, якщо перед цим не задекларувати її глобальною використавши ключове слово global[11].

У Python ідея просторів імен реалізована у модулях. (Так само, як і у пакетах Java)

За замовчуванням[en] всі ідентифікатори знаходяться в глобальному просторі назв, тому часті випадки існування двох різних об'єктів з однаковими назвами, що призводить до помилок. Щоб цьому запобігти глобальний простір назв ділять на менші. Наприклад стандартну бібліотеку C++ винесено в область названу std.

Простір імен визначається блоком інструкцій, а саме:

namespace foo {
  int bar;
}

Усередині цього блоку ідентифікатори можуть викликатися у той спосіб, яким вони були оголошені. Важливо, що поза блоком потрібна вказівка назви простору імен перед ідентифікатором. Наприклад, поза namespace foo ідентифікатор bar має вказуватися, як foo::bar . У мові C ++ містяться деякі інші конструкції, які роблять подібні вимоги необов'язковими. Так, при додаванні рядка:

using namespace foo;

Більше не потрібно вказується префікс foo::у код, . Ще один приклад:

namespace Namespace12
{
  int foo=0;
}

void func1()
{
  using namespace Namespace12;
  // тепер всі імена з простору імен Namespace12 буде видно тут без додаткових префіксів

  ++foo;
}

void func2()
{
  // а тут ім'я потрібно уточнити:
  Namespace12::foo = 42;
}

Код, який не оголошено явно у просторі імен, за замовчуванням, вважається оголошеним у глобальному просторі імен.

Дозвіл просторів імен в C ++ прописується ієрархічно. Це означає, що у гіпотетичному просторі назв їжа::бульйон, ідентифікатор курка буде позначати їжа::бульйон::курка (якщо простір існує). У випадку, якщо не існує, то тоді він перепосилається на їжа::курка (такий простір існує). Якщо ж і цей простір не існуючий-то: курка посилається на ідентифікатор у глобальному просторі.

Зазвичай, простір імен у C ++ використовується для уникнення випадків колізій імен

namespace {
  int a;
  void f() { /*...*/ }
  int g() { /*...*/ }
}

Неможливо здійснити доступ з однієї одиниці трансляції до частини анонімного простору імен до іншої одиниці.

Хоча простір імен активно використовуються у сучасному коді, значна частина старого коду не має подібних можливостей. Наприклад, уся стандартна бібліотека мови C ++ визначена всередині namespace std , але до стандартизації багато компонентів спочатку були визначені у глобальному просторі.

Також можна зробити відкритим до перегляду не весь простір, а окремі імена всередині нього, наприклад:

namespace foo {
  int bar;
  int somelse;
}
int main () {
 using foo::bar; //Робить видимим тільки bar, somelse невидимий!
 return 0;
}

Створення просторів назв

[ред. | ред. код]

Щоб створити простір назв використовують ключове слово namespace. Код:

namespace <назва_простору>
{
   // Оголошення
}

Доступ до ідентифікаторів з просторів назв

[ред. | ред. код]

Щоб отримати доступ до об'єктів з простору назв з за його меж використовують оператор дозволу області видимості ( :: ). Наприклад:

namespace some
{
    int something;
}
something=1; // Помилка, something невидиме.
some::something=1; // Ми вказали в якій області його шукати.

Правда такий спосіб може бути незручним, якщо ми використовуємо багато ідентифікаторів не з нашої області видимості. Щоб полегшити нам життя придумана директива using. Хай ми маємо простір кімнати:

namespace room
{
   Wall wall1, wall2, wall3, wall4;
   Ceil ceil;
}

Можна внести стелю в наш простір назв, написавши, що ми її будемо використовувати:

using room::ceil;
ceil = 42; // Тепер стеля видима
wall1 = wall2; // А таке все ще викличе помилку!

А можна взагалі розкрити увесь простір назв:

using room;
wall1 = wall2 = wall3; // Всі ідентифікатори з кімнати доступні

Мова надає можливість для реалізації просторів імен, незважаючи на відсутність формальної підтримки, використовуючи об'єктну концепцію мови:

var NameSpace_1 = {};
var NameSpace_2 = new Object(); //Створюються два простори імен

NameSpace_1.a = 100;
NameSpace_2.a = "Суниця";    //Змінні a - у кожного свої

with(NameSpace_1)      //Вказуємо простір імен за замовчуванням
{
 a += 10;
 NameSpace_2.a += a;   //Змінна a простору імен NameSpace_2 дорівнюватиме "Суниця110"
}

У XML специфікація просторів XML імен визначає унікальність імен елементів і атрибутів у документі, аналогічно ролям просторів імен у мовах програмування. За допомогою просторів імен XML-документи можуть містити імена елементів або атрибутів з більш ніж одного словника XML.

<rdf:RDF
  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  xmlns:foaf="http://xmlns.com/foaf/0.1/"
  xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">
  <foaf:Person rdf:about="#JW">

xmlns (XML Namespace) - простір імен XML. Підключаються RDF (для створення документа RDF ), FOAF і RDF Schema ( формат оформлення RDF ).

FOAF — це теж простір RDF документа, тому перевіряється його оформлення згідно зі словником (правилами, специфікації) RDF.

Починаючи з версії 5.3.0 у PHP введено поняття простору імен.

<?php
namespace my\name; // визначимо новий простір імен

class MyClass {}
function myfunction() {}
const MYCONST = 1;

$a = new MyClass; // виклик всередині простору my\name
$c = new \my\name\MyClass; // використовуємо повне ім'я, яке включає назву простору імен
$d = new \globalClass; // звернення до класу з глобального простору імен
?>

Важливо те, що директива namespace повинна бути першим рядком коду у файлі. Виняток є ключове слово declare, яке може передувати директиві namespace. Не допускається, навіть, виведення HTML перед першою конструкцією «<?php».

Опис синтаксису є на офіційному сайті проекту PHP[12].

У стандартному синтаксисі Common Lisp є табличні простори імен, які реалізуються через систему пакетів[13]. Необхідно вказати назву ідентифікатора (символу) для використання, а саме: повну назву (назва пакету, двокрапка та назва самого символу)[14].

У Allegro Common Lisp реалізовано нестандартне розширення Common Lisp - ієрархічний простір імен, де пакети розділяються використанням крапки, у стилі Java , а ідентифікатор від пакетів відокремлюється двокрапкою. Також, можливі звернення до суміжних вузлів в ієрархії просторів імен через посилання до відносних шляхів, використовуючи двокрапку[15]. Простори імен у Common Lisp є динамічними - вони створюються, наповнюються і знищуються під час виконання програми, хоча здебільшого застосовується декларативна форма їх опису за допомогою форми defpackage [16] .

PureBasic

[ред. | ред. код]

У PureBasic 5.20 , була введена підтримка простору імен, реалізована у вигляді модулів. Простір імен визначається блоком команд Module і EndModule і не залежить від розташування у первинних файлах. Це означає, що в одному файлі, можуть існувати декілька модулів, чи навпаки - код модуля може бути розділений на декілька файлів. За замовчуванням, увесь простір модуля приховано, для того щоб зробити видимим окремі його елементи, їх необхідно оголосити у спеціальному блоці команд DeclareModule / EndDeclareModule. Усе, що не оголошено у цьому блоці, не можливо переглянути поза межами модуля, і спроба доступу приведе до повідомлення компілятора про порушення прав доступу.

DeclareModule Count
  x=0 ; Public elements
  Declare Counter()
EndDeclareModule

Module Count

  y=0 ; Private elements

  Procedure Counter()
    y+1
    ProcedureReturn y
  EndProcedure

EndModule

Count::x = 10 ; Запис числа у змінну (для прикладу).
Debug Count::Counter() ; Виклик процедури, що використовує ім'я модуля.

UseModule Count ; Відображення модуля у дійсний простір.
Debug Counter() ; Відкритий доступ (Public) до елементів без вказівок на ім'я модуля.
UnuseModule Count ; Скасування дії UseModule.

Для отримання доступу елементів модуля з іншого модуля або глобального простору, необхідно вказати ім'я модуля і його елемент. Наприклад: Count :: x. Також, можна використати команду UseModule, яка дозволяє відобразити всі видимі елементи модуля до поточного простору. Команда UnuseModule скасовує цю дію. Одночасне відображення видимих елементів декількох модулів можливе, за умови попереджання проблеми конфлікту імен. Припустимо, що у проекті є модулі з іменами x, y і z.

UseModule x
UseModule y
; Код.
UseModule z

; Ще код.

UnuseModule y
; Ще код.
UnuseModule x
UnuseModule z

Цей приклад відображає можливість відображання у поточний простір декількох модулів, а також особливість, що не важлива послідовність відображення елементів модулів і його скасування.

Мови програмування без власної підтримки просторів імен простору можуть емулюватися розширенням, використовуючи угоди про найменування ідентифікаторів Прикладом цього є, бібліотеки мови С, такі як Libpng, часто використовують фіксований префікс для всіх функцій і змінних, що є частиною їх зовнішнього інтерфейсу. Libpng підтримує зовнішні ідентифікатори, такі як:

png_create_write_struct
png_get_signature
png_read_row
png_set_invalid

Це надає обґрунтовану гарантію, що ідентифікатори будуть унікальні і, таким чином, можуть бути використані у великих програмах без побоювання колізії імен ідентифікаторів .

Далі перераховані недоліки емуляції просторів імен [ джерело не вказано +1910 днів ]

  • Відсутній нормально функціонуючий облік вкладених просторів; ідентифікатори подовжуються занадто.
  • Програмісти/організації можуть використати різко несумісні угоди про найменування, тим самим потенційно провокуючи велику заплутаність.
  • Складні операції чи операції запиту над групами ідентифікаторів, заснованих на просторі імен, де вони оголошені, обробляються занадто неоптимально, інколи, взагалі нездійсненні.
  • Усі виклики ідентифікаторів повинні здійснюватися з повним ім'ям просторів

Мови з безпосередньою підтримкою просторів імен, зазвичай, надають програмісту можливість попередньо оголошувати, що він хоче використовувати деякі (а то і всі разом) ідентифікатори у програмі тільки з одного простору, які вони згодом можуть використовувати без вказівки належності до простору.

Деякі особливості просторів назв

[ред. | ред. код]

Можна робити простори назв без назви. Це просто для того, щоб зробити локальні змінні невидимими поза областю. Крім того можна описувати кілька просторів назв з одною назвою. Тоді це буде один, і той же простір, просто рознесений в різні частини файлу, чи взагалі в різні файли.

Неназваний простір назв або простір назв визначений прямо чи непрямо в неназваному просторі назв3 має внутрішнє зв'язування (англ. internal linkage).[17]

Див. також

[ред. | ред. код]

Примітки

[ред. | ред. код]
  1. Дудзяний, І. М. (2006). Програмування мовою Visual Basic .NET (PDF). Львів: Видавничий центр ЛНУ імені Івана Франка. с. 9, 20. Архів оригіналу (PDF) за 2 квітня 2018. Процитовано 1 квітня 2018.
  2. Сопронюк, Т. М. (2007). Microsoft Visual Basic та його діалекти (PDF). Чернівці: ЧНУ. с. 55—56. Архів оригіналу (PDF) за 2 квітня 2018. Процитовано 1 квітня 2018.
  3. Парфьонов, Ю. Є.; Федорченко, В. М.; Лосєв, М. Ю.; Щербаков, О. В. (2010). Об'єктно-орієнтоване програмування: конспект лекцій для студентів напряму підготовки "Комп'ютерні науки" всіх форм авчання (PDF). Харків: Вид. ХНЕУ. с. 13—14. Архів оригіналу (PDF) за 10 січня 2017. Процитовано 4 липня 2022.
  4. Фурник, Р. В.; Ромадін, Р. В. (2011). Соціальні сервіси Веб 2.0 та основні напрямки їх використання в освіті (PDF). Черкаси. с. 19—20, 25. Архів оригіналу (PDF) за 23 січня 2022. Процитовано 24 березня 2022.
  5. Литвин, В. В. (2010). Пасічник, В. В. (ред.). Технології менеджменту знань. Консолідована інформація. Львів: Видавництво Львівської політехніки. с. 189, 216. ISBN 978-966-553-975-9.
  6. Парфьонов, Ю. Є.; Федорченко, В. М.; Лосєв, М. Ю.; Щербаков, О. В. (2010). Об'єктно-орієнтоване програмування: конспект лекцій для студентів напряму підготовки "Комп'ютерні науки" всіх форм авчання (PDF). Харків: Вид. ХНЕУ. с. 98—101, 156, 197, 243, 261, 298, 305. Архів оригіналу (PDF) за 10 січня 2017. Процитовано 4 липня 2022.
  7. Грицюк, Юрій; Рак, Тарас (2011). УІБ/Грицюк Ю.І/C++.pdf Програмування мовою C++ (PDF). Львів: Вид-во ЛДУ БЖД. с. 36. ISBN 978-966-3466-85-9.[недоступне посилання з липня 2019]
  8. Python Built-in Functions — locals(). Архів оригіналу за 8 грудня 2017. Процитовано 7 грудня 2017.
  9. Python Built-in Functions — globals(). Архів оригіналу за 8 грудня 2017. Процитовано 7 грудня 2017.
  10. Python Built-in Functions — dir(). Архів оригіналу за 8 грудня 2017. Процитовано 7 грудня 2017.
  11. Python Language Reference — 7. Simple statements — The global statement. Архів оригіналу за 8 грудня 2017. Процитовано 7 грудня 2017.
  12. PHP: Використання простору імен: основи — Manual. Архів оригіналу за 31 січня 2019. Процитовано 30 січня 2019.
  13. Packages (англ.). www.cs.northwestern.edu. Архів оригіналу за 24 грудня 2018. Процитовано 23 грудня 2018.
  14. Source Code Organisation. lispmethods.com. Архів оригіналу за 16 березня 2019. Процитовано 23 грудня 2018.
  15. Hierarchical Packages (англ.). franz.com. Архів оригіналу за 24 грудня 2018. Процитовано 10 червня 2017.
  16. CLHS: Macro DEFPACKAGE. www.lispworks.com. Архів оригіналу за 1 лютого 2019. Процитовано 10 червня 2017.
  17. ISO/IEC 14882:2011, 3.5 Program and linkage.

Посилання

[ред. | ред. код]