Вывод Типов В Программировании

При написании алгоритмов часто возникает ситуация, когда какую-то функцию нужно вызвать с одинаковым количеством аргументов, но с разными типами.

Давайте решим.

Надуманный пример на C++:

  
  
  
  
   

#include <iostream> #include <string.h> using namespace std; void a(int x) { cout<<"number\n"; } void a(float x) { cout<<"number\n"; } void a(const char *x) { cout<<"string\n"; } template <typename T> void f(void(*g)(T x), T x) { g(x); } int main() { f(a, 1); f(a, 1.0f); f(a, "Alexey"); return 0; }

Тот же код в Javascript:

function f(g, x) { g(x) } function a(x) { alert(typeof x) } f(a, 1) f(a, 1.0) f(a, 'Alexey')

Очевидно, что код JavaScript лучше.

Давайте разберемся, почему это происходит.

Динамический подход

В javascript каждая переменная имеет свойство type, которое возвращается, когда к переменной применяется оператор typeof. Это свойство сохраняется во время выполнения программы, когда переменная существует. И когда к переменной применяется какой-то оператор, функция, реализующая этот оператор, проверяет тип переменной.

В зависимости от типа выполняются некоторые действия.

Например, 2+2 вернет 4, 2+"Алексей" вернет "2Алексей".

Те.

Операторы языка почти всегда обязаны проверять типы переменных, к которым они применяются.

Назовем этот подход «динамической типизацией».

Недостатки такого подхода вполне очевидны, а точнее один из них – необходимость производить дополнительные вычисления во время выполнения программы.

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

Еще одним преимуществом станет код, в котором нет необходимости дублировать значительную часть логики.

Это слегка видно в примере выше — функция f реализуется один раз, но результат ее выполнения зависит от переданной в нее функции, реализующей различную логику.



Статический подход

Язык C требует указания типа переменной и запрещает его изменение.

В результате во время выполнения программы проверки типов не выполняются; операторы применяются к переменным однозначно.

Но красивых механизмов обобщения не существует. Что это такое: универсальный указатель void*, возможность передать в функцию указатель на другую функцию.

В языке C++, который в некотором роде является расширением языка C, появились такие механизмы, как полиморфизм функций (перегрузка) и шаблоны.

Полиморфизм функций позволяет вам назвать две функции, которые делают одно и то же, но с разными типами данных и одинаковыми именами.

Шаблоны представляют новый тип, общий для всех типов.

Эти механизмы хороши тем, что с их помощью без участия программиста подставляются функции нужных типов.

Те.

если один шаблон функции использует 2 разных типа, то во время компиляции будут созданы 2 разные функции.

При вызове исходной функции в коде в скомпилированный файл будет подставлен вызов скопированной функции нужного типа.

Преимущества подхода: максимальная скорость выполнения.

Минусы: для выполнения требуется больше памяти.



Вывод типа

Другими словами, когда необходима максимальная производительность и достаточно памяти, статический подход более предпочтителен.

Но при выборе, скажем, языка C++ теряется читаемость кода.

Ведь для каждого чиха приходится указывать тип, с которым вызывается функция.

Например, код быстрой сортировки:

#include <iostream> #include <string.h> using namespace std; template<class T> void qsort(T** array, int length, int compare(T *a, T *b)) { int left = 0; int right = length-1; T *middle_element; middle_element=array[length/2]; do { while( compare(array[left], middle_element)<0 ) left++; while( compare(array[right], middle_element)>0 ) right--; if(left<=right) { swap(array[left], array[right]); left++; right--; } } while(left<=right); if(right>0) qsort(array, right, compare); if(left<length) qsort(array+left, length-left, compare); } int cmp(char *a, char *b) { return strcmp(a, b); } int main() { char *strings[]={"Alexey", "Borisenko"}; qsort(strings, 2, cmp); return 0; }

Полностью удалив типы, вы только улучшите читабельность:

#include <iostream> #include <string.h> using namespace std; qsort(array, length, compare) { left = 0; right = length-1; middle_element = array[length/2]; do { while( compare(array[left], middle_element)<0 ) left++; while( compare(array[right], middle_element)>0 ) right--; if(left<=right) { swap(array[left], array[right]); left++; right--; } } while(left<=right); if(right>0) qsort(array, right, compare); if(left<length) qsort(array+left, length-left, compare); } cmp(a, b) { return strcmp(a, b); } main() { strings={"Alexey", "Borisenko"}; qsort(strings, 2, cmp); return 0; }

Из этих соображений был сделан вывод, что отказ от типов — хорошая идея.

Давайте подумаем, как это реализовать.

Существует 3 основных типа: 1) Простой 2) Композитный 3) Функция Простой тип включает в себя все типы, которые не содержат других (строка, число, массив.

).

Соответственно, для составления составных структур, таких как гетерогенный массив, структура и т. д. Функция выделяется тем, что у нее есть аргументы, которые сами являются типами.

Итак, вывод типа осуществляется в ходе следующих операций: 1) Назначение 2) Вызов функции Во время вывода типа переменная не может изменить тип.

Доказательство от противного:

f(a) { x=1 if(a<2)

Теги: #выведение типа #JavaScript #программирование #C++ #Алгоритмы #C++

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.