Для чого змінним потрібен тип?


10

Тому пишемо:

Customer c = new Customer();

Чому дизайн не такий, про який ми пишемо:

c = new Customer();
c.CreditLimit = 1000;

Компілятор може розробити c пункти до Клієнта та дозволити членам Замовника викликати c?

Я знаю, що ми можемо захотіти написати:

IPerson c = new Customer();
IPerson e = new Employee();

щоб мати можливість писати:

public string GetName(IPerson object)
{
    return object.Name
}

string name = GetName(c); // or GetName(e);

Але якщо ми написали:

c = new Customer();
e = new Employee();

ми ще могли написати:

public string GetName(object)
{
    return object.Name
}    

string name = GetName(c); // or GetName(e);

Компілятор може скаржитися на код безпосередньо вище, якщо тип посилань на об'єкт c не підтримує властивість Name (оскільки він може перевірити, які члени використовуються в аргументі / параметрі в рамках методу), або час виконання може скаржитися.

Навіть з динамічним ключовим словом C # ми все ще використовуємо змінну 'type' (визначається під час виконання). Але навіщо змінній взагалі потрібен тип? Я впевнений, що має бути вагома причина, але я не можу про це думати!


12
Ось чому існують такі динамічні мови, як Python та Ruby (та інші). На це питання немає відповіді . Справа в тому, що деякі мови використовують декларації типів, а деякі - ні.
S.Lott

2
"змінні в цих мовах взагалі не мають типу?" Правильно. змінні не мають типу в Python. Об'єкти мають тип, а змінні - просто посилання на об'єкти. Ваше питання насправді лише спостереження. Зокрема, "не всі мови вимагають змінних оголошень". Відповіді немає. Тож цілком ймовірно, що він закриється як неконструктивний.
S.Lott

1
Ви можете поглянути на Boo , який дозволяє вам оголошувати змінні без будь-яких оголошень типу, але використовує умовиводи, щоб визначити типи, щоб ви не жертвували правильністю та перевагами продуктивності при сильному введенні тексту.
Мейсон Уілер

2
var x = 1; - ти мав на увазі 32-бітове, 64-бітове, 16-бітове число? байт? плавати? подвійний? десятковий? Це просто справа з примітивами.
Робота

4
Ви можете використовувати varв C # і пояснювати, де ви хочете оголосити змінну, завжди добре.
Даніель Літтл

Відповіді:


22

Але навіщо змінній взагалі потрібен тип?

  1. Це може спричинити помилки, коли змінній присвоєно неправильне, неправильно набране вираз. У деяких мовах є динамічне введення тексту , яке приносить у жертву гарантії правильності типу для змінної для тієї гнучкості, якої ви, схоже, бажаєте.
  2. Типи можуть дозволити компілятору генерувати більш ефективний код. Динамічні засоби набору тексту перевірки типу повинні виконуватися під час виконання.

1
Поясніть будь-ласка.
Фред Фоо

4
Крім того, динамічне введення тексту відбувається за ефективність, оскільки інформацію про тип потрібно перевірити під час виконання.
Шарль Сальвія

@CharlesSalvia: хороший момент, додав це до відповіді.
Фред Фоо

2
@sturdytree: що стосується "якщо він не має типу, то він не може бути неправильно введений" - що стосується мовних правил, це правда. Але змінній все ж може бути призначений неправильний тип з семантичної точки зору, наприклад, ви неправильно ввели ім'я конструктора і програма все ще працює, але не робить те, що вам потрібно.
Фред Фоо

5
@sturdytree Хоча це правда, що не існує мов, які мають справді безхарактерні змінні при перевірці типів, є мови, які мають умовивід . Тобто мова вивчає ваше використання змінної та виводить тип із вашого використання. Якщо виникає конфлікт (наприклад, ви виконуєте a = new Bar()та потім викликаєте метод з класу Baz), компілятор викликає помилку. Такі мови, як Haskell та OCaml, є піонерським висновком типу, але він присутній у C #, з varключовим словом.
кількість

9

У вас є абсолютно дійсна точка, мови, які не відстежують тип змінної, існують і називаються "динамічно набраними". Категорія включає такі мови, як JavaScript, Perl, Lisp та Python.

Перевага, яку ми отримуємо від статично набраної мови, - це додаткова перевірка помилок під час компіляції.

Припустимо, наприклад, що у вас є такий метод:

public addCustomerContact(Customer client, Employee contact) {
   ...
} 

Можливо, якщо у коді є клієнт bobі працівник james, помилково зателефонувати addCustomerContact(james, bob), що недійсно. Але якщо компілятор не знає типів змінних, він не може попередити вас про те, що ви зробили недійсний виклик, натомість під час виконання виникає помилка ... і оскільки динамічно набрані мови не перевіряють тип параметрів, переданих методам, ця проблема виникає щоразу, коли ваш код намагається використовувати властивості jamesоб'єкта, призначені лише для клієнта , або властивості bobоб'єкта лише для працівника . Це може пройти довго після того, як пара (Джеймс, Боб) була додана до списку контактів клієнтів.

Тепер ви можете задуматися, чому компілятор не може зробити висновок про тип jamesта bob, і все ще попередити нас? Іноді це можливо, але якщо змінні дійсно не мають типу, ми можемо зробити наступне:

var james;
var bob;
if (getRandomNumber() > 0.5) {
   james = new Customer();
   bob = new Employee();
} else {
   james = new Employee();
   bob = new Customer();
}

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

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

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


Дякую Теодору. "Але якщо компілятор не знає типів змінних, він не може попередити вас про те, що ви зробили недійсний виклик". Як згадуєте, компілятор може знати типи об'єктів, на які вказують змінні.
міцне дерево

Теодор: У вашому прикладі Джеймс / Боб, ми, як програмісти, повинні знати, як ми використовували наші змінні (і добре іменування допомагає), і тому я не бачу в цьому проблеми. Коли ви говорите: "ми не завжди можемо знати тип змінної" застосовано (тобто ми можемо мати статичну перевірку).
міцне дерево

2
Я наводив приклад вище, в якому ви не можете статично знати типи об’єктів ... залежно від шляху виконання, тип об'єкта, що зберігається у змінній без інформації про тип, може бути різним. Ви можете мати мову на зразок C #, на якій можна зробити висновок про тип компіляції, але, наскільки я знаю, немає мови як зі статичними типами перевірки типу, так і зі справді типовими змінними, обчислювальна складність статичного аналізу, ймовірно, теж чудовий.
Теодор Мердок

Теодор, спасибі, ви правильно зрозуміли, що я говорю про мову зі статичною перевіркою типу (на основі типу об'єкта) та безтипними змінними. Сумно почути, що таких немає - мені кажуть, що в Python є безцінні змінні, але звучить так, що у нього немає статичної перевірки типу.
міцне дерево

1
-1; сильне / слабке введення є ортогональним до статичного / динамічного введення тексту. C статично слабо типізований; Липп та Python динамічно сильно набрані.
Фред Фоо

5

Тож професійним програмістам не потрібно зрозуміти, чи є

10 + "10"

is "1010" or 20....

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


2
Тобто, Perl - це не розумна мова? :)
Фред Фоо

5
@larsmans: власне, ні, це не так. але це суто думка.
NotMe

2
@ChrisLively: Я радий, що це вже справа. Будь-ласка, будь-коли приходьте на моє робоче місце, щоб переконати своїх колег, що люблять;)
Фред Фоо

2
10 + "10" використовує оператор "+" для об'єкта цілого типу та об'єкта рядкового типу. Компілятор видасть помилку. Моє запитання стосується типу змінної, а не об'єкта.
міцне дерево

2
Він є дійсним C: Це покажчик арифметика.
dan04

4

Припустимо, що у вас була змінна one(встановлена ​​на 1) і спробували оцінити one + one. Якщо ви не мали уявлення про тип, то 1 + 1 буде неоднозначним. Ви можете стверджувати, що 2 або 11 можуть бути правильними відповідями. Це стає неоднозначним, якщо контекст не заданий.

Я бачив, що це відбувається в SQLite, де типи баз даних були ненавмисно встановлені VARCHARзамість, INTі коли операції проводилися, люди отримували несподівані результати.

У c #, якщо контекст визначає тип, ви можете використовувати varключове слово.

var c = new Customer();
var e = new Employer();

Буде компілювати c і e із виведеними типами під час компіляції.


1
У Python 1 + 1завжди є тип int, але декларувати це не потрібно. Питання полягає в тому, чому змінні мають тип, а не значення .
Фред Фоо

Вибачте, що ви мали намір бачити variablesне те, valuesколи я використовував 1 + 1у своєму прикладі. Я думаю, це було не ясно.
Стівен Куан

Проте динамічно набрані мови можуть з цим впоратися. У Python one=1; print(one+one)друкується 2. one="1"; print(one+one)відбитки 11. Приклад SQLite є більш переконливим, але проблема полягає в слабкому наборі тексту, тому це не дуже актуально для C #.
Фред Фоо

У моїй запропонованій схемі один = 1 означає змінну, що вказує на цілий тип (я взагалі не пропоную жодних типів - об’єкти матимуть тип). тоді один + один не був би неоднозначним (ми додаємо два цілих об'єкти / значення)
міцне дерево

1
Привіт @ dan04, я бачив це з ORDER BYненавмисно зробленим на VARCHARполі. Дивіться stackoverflow.com/questions/9103313/… .
Стівен Куан

4

Змінна не повинна мати асоційований тип. Мови, де це відповідає дійсності, включають Lisp, Scheme, Erlang, Prolog, Smalltalk, Perl, Python, Ruby та інші.

Можливо також, що змінна має тип, але можливо, вам не доведеться писати тип у програмі. Зазвичай це називається виведенням типу. ML, Haskell та їхні нащадки мають потужні умовиводи; деякі інші мови мають його в менших формах, наприклад, autoзаяви C ++ .

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


1

Коли ви визначаєте тип, який представляє ваша змінна, ви робите заяву про пару речей. Ви визначаєте вимоги щодо розподілу пам'яті для вашої змінної та визначаєте правила сумісності та діапазону для своєї змінної. Він надає спосіб уникнути плутанини у ваших намірах щодо даних, які ви зберігаєте, та надати вам порівняно дешевий спосіб виявити потенційні проблеми у вашому коді під час компіляції.

Якщо ви декларуєте такі змінні:

myVar      = 5;
myOtherVar = "C";

Що ви можете зробити на основі цих змінних? Є myVarзнаком або без знаку? Це 8-бітний, 64-бітний або щось середнє? Це myOtherVarString (фактично масив) чи Char? Це ANSI чи Unicode?

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

Ще одним моментом із сильно набраними мовами є те, що це позбавляє вас від необхідності надавати інструкції компілятору щоразу, коли ви використовуєте змінну. Чи можете ви уявити, яким жахливим і нечитабельним став би ваш код, якби кожен раз, коли ви зверталися до змінної, ви змусили її ефективно передавати, щоб сказати компілятору, який саме це значення? !!


Хороший момент, хоча компілятор міг би просто використовувати найефективніший тип (наприклад, невеликий int) на основі значення, я можу побачити, що ми можемо хотіти, щоб "C" був об'єктом рядка, а не char, щоб мати можливість виконувати певні операції . Однак у таких випадках ми можемо просто вказати a = (string) "C". Це створює об'єкт рядка і 'a' (типізована змінна) просто вказує на нього. Я не вважаю це більш жахливим, ніж рядок a = "C";
міцне дерево

0

Комп'ютерна програма - це графік вузлів процесу, що описує, що має робити "машина", представлена ​​мовою виконання (розширена набір інструментів у більшості випадків), у якому порядку чи за яких умов. Цей графік представлений текстовим файлом (або купою текстових файлів), написаним певною мовою, і (частково або повністю) створений, коли компілятор / інтерпретатор читає (десеріалізує) цей файл. Також є деякі середовища (інструменти для створення UML або графічної програми), де ви можете фактично скласти цей графік та генерувати вихідний код цільовою мовою.

Чому я це кажу? Тому що це призводить до відповіді на ваше запитання.

Текст програми - це ваші вказівки щодо того, як комп’ютер повинен вирішити фактичну задачу, що містить як етапи процесу (умови, дії), так і структуру (які компоненти ви використовуєте в рішенні). Останнє означає, що ви отримуєте або створюєте деякі екземпляри інших компонентів, поміщаєте їх у названі поля (змінні) та використовуєте їх: отримуйте доступ до своїх даних та послуг.

Деякі мови надають уніфіковані поля, де важлива лише мітка, але ви можете помістити в них просто все, ви навіть можете використовувати змінну з назвою "target" для зберігання "Person" на початку та "Car" в кінці той же алгоритм. Інші вимагають, щоб ви створили "фігурні" коробки, тому різні для особи чи машини - хоча вони все ще дозволяють вам створити "загальну коробку" (Java Object, C / C ++ void *, ціль C "id" ...) і киньте, як вам подобається. Введені мови дозволяють висловлювати вашу структуру більш дрібними деталями, створюючи "контракти типу" для своїх змінних (хоча ви можете зламати це обмеження), тоді як нетипізовані мови підтримують це "Я точно буду знати, що я вклав у цю рамку цього разу" підхід як поведінка за замовчуванням і тільки.

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

Я думаю, що зайве говорити, що я віддаю перевагу правилам фокусам, особливо для довгострокових, великих командних проектів (також: "серйозних") проектів. Причина: наскільки я знаю, найбільш вірогідними причинами провалу / ковзання проекту SW є: незрозумілі вимоги та поганий дизайн (80%! Дослідження, яке я знаю), і лише фактичне кодування залишається на кілька відсотків. Усі правила та договори застосовують більш чіткий дизайн, задумуючись вперед, і вимагає, щоб рішення були прийняті раніше і від належних людей. Типи означають правила: менше "свободи" та "прохолоди" - більше підготовки, мислення, стандартів кодування, контрольована командна робота. Мені це звучить як необхідний фактор успіху, а також «домашній, милий дім».

Мої 2 копійки.


-3

AFIAK всі мови з динамічним набором тексту інтерпретуються. Це вже дуже неефективно, додавання неефективності динамічного набору тексту не буде великою втратою часу. Однак компільована мова фактично не посилається на речі за назвою, коли вона працює. (Якщо забороняти періодичне використання .net-відображення тощо) - функції, які дуже повільні порівняно з базовою мовою.) Пошук усіх цих імен буде повільним, повільним, повільним.


3
Ви неправильно знаєте. Існує багато компіляторів для динамічно набраних мов, а деякі з них досить швидкі. Приклади включають загальні Lisp, Scheme та Erlang.
Райан Калпеппер,

3
Немає такого поняття, як "інтерпретована мова". Мова - це абстрактний набір математичних правил. Мова ні компілюється, ні інтерпретується. Мова просто є. Компіляція та інтерпретація є рисами реалізації, а не мовою. Кожна мова може бути реалізована за допомогою перекладача, а кожна мова може бути реалізована за допомогою компілятора. І майже кожна мова має як інтерпретовані, так і компільовані реалізації, наприклад, є інтерпретатори для C та компілятори для ECMAScript, Ruby та Python.
Йорг W Міттаг

-4

Динамічно набрані мови часто рекламуються як "об'єктно-орієнтовані". Вони не. Вони можуть бути орієнтованими на інкапсуляцію, але ніколи не орієнтовані на об'єкти. Об'єктна орієнтація стосується типів.

"Хлопчик їде на велосипеді брата до продуктового магазину та купує у бакаліну хліб". Використовуючи орієнтацію на об'єкт, можна негайно написати набір класів (типів) для опису цього сценарію реального світу.

У динамічно набраній мові сценарій може бути представлений лише таким чином:

"Об'єкт їде до об'єкта свого об'єкта і купує об'єкт у об'єкта".

Сила орієнтації на об'єкт полягає в його здатності моделювати світ у природних рисах, щоб розробник програмного забезпечення міг використовувати обидві сторони мозку для написання програмного забезпечення та вирішувати проблеми більше як людину, менше - як комп'ютерний програміст. Ця динаміка відсутня в динамічно набраних мовах.

Статична типізація дозволяє підвищити ефективність кодування, повторну використання та ремонтопридатність, оскільки інтегровані середовища розробки знають типи змінних. Знаючи типи змінних, IDE може забезпечити автоматичне завершення, щоб програмісту не довелося повертатися до визначення класу, щоб пам’ятати, чи було написано властивість члена «backlightControl» або «backLightControl» чи «bkLightCtrl».

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

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


2
Боюся, що мені доведеться не погодитися з вами в першій частині вашої аргументації. Мови, що динамічно вводяться, як правило, "об'єктно-орієнтовані", але не "орієнтовані на клас". Це важлива відмінність. У вашому прикладі ви насправді живете в ілюзії. У вас може бути Boyклас, але я сумніваюся, він може зробити все, що робить "хлопчик" у реальному світі. Однак у вашому динамічному прикладі (Об'єкт їде ...) ми знаємо єдине важливе, що стосується цього "хлопчикового" об'єкта - він може їздити . Це основна філософія мов динамічного типу. Він має + ve s і -ve s. Хто вам подобається - це ваша думка.
Чіп
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.