Category Archives: Перегрузка функций

Какие функции вызывает Swift? Часть 5: Range против Interval.

Это русский перевод статьи airspeedvelocity Which function does Swift call? Part 5: Range vs Interval

Это часть 5 из серии постов о том, как Swift разрешает “неоднозначность” в “перегруженных” функциях. Часть 1 можно найти  здесь (русский перевод – здесь). В предыдущей статье (русский перевод – здесь), мы рассматривали как управлять  generics.

И наконец …

Теперь, когда мы рассмотрели как подбираются  generics, мы можем наконец ответить на первоначальный вопрос – как мы получаем тип  Range по умолчанию для выражения 1...5 ? Вот образец кода:

// r будет иметь тип Range<Int>
let r = 1...5

// если вы хотите такой тип ClosedInterval<Int>, то вам
// нужно задать тип явно:
let integer_interval: ClosedInterval = 1...5

// если вам нужен тип Doubles, то нет необходимости
// декларировать тип явно.
// floatingpoint_interval is a ClosedInterval<Double>
let floatingpoint_interval = 1.0...5.0

Функция, соответствующая infix оператору  ...  , определяется трижды в стандартной библиотеке со следующими сигнатурами:

func ...<T : Comparable>
  (start: T, end: T) -> ClosedInterval<T>

func ...<Pos : ForwardIndexType>
  (minimum: Pos, maximum: Pos) -> Range<Pos>

func ...<Pos : ForwardIndexType where Pos : Comparable>;
  (start: Pos, end: Pos) -> Range<Pos>

Первые две – очень простые. Они обе generic, у них единственная generic метка-заполнитель (placeholder), которая ограничена единственным протоколом. Нет преимущества у одного ограничения перед другим.

Оба протокола Comparable и ForwardIndexType происходят из протокола Equatable, но ни один из них не происходит от другого. Если мы оставим только эти две функции, то мы получим ошибку “неоднозначности” –ambiguous call error.

Но есть третья функция, которая и заставляет Swift выбрать Range , а не  ClosedInterval. В этой функции, Pos ограничивается не только ForwardIndexType, но и Comparable. Ограничение двумя протоколами выигрывает у ограничения с одним, так что при “перегрузке” будет выбрана эта функция.

Continue reading

Какие функции вызывает Swift? Часть 4: Generics.

Это русский перевод статьи airspeedvelocity “Which function does Swift call? Part 4: Generics”.

Это 4 часть из серии статей, посвященных тому, как выбираются “перегруженные” (overloaded) функции в Swift. Часть 1 рассматривает “перегрузку” (overloading) по типу возвращаемого значения, часть 2 о том, как различные функции с простым одним аргументом выбираются по принципу “наиболее подходящей” функции, и часть 3 раскрывает этот принцип более детально в плане протоколов.

Мы начали серию статей с вопроса, почему мы получаем тип Range для 1…5 вместо типа  ClosedInterval? Сегодня мы разберем как  generics вписываются в иерархию “наиболее подходящей” функции, и у нас наконец будет достаточно информации для ответа на вопрос.

Generics – это более низкий приоритет

Continue reading

Какие функции вызывает Swift? Часть 3: Композиция протоколов.

Это русский перевод статьи airspeedvelocity “Which functions does Swift call? Part 3: Protocol Composion”

В предыдущих статьях мы исследовали,  как функции Swift могут быть “перегружены” только по возвращаемому типу, и как Swift выбирает между различными возможными “перегрузками” с помощью механизма “наилучшего соответствия” ( best-match mechanism).

Эти исследования мы провели с целью выяснения причины, почему  1…5 возвращает тип Range а не тип ClosedInterval. И для понимания этого нам нужно рассмотреть как generics работают с критериями “наилучшего соответствия”.

Но прежде чем мы этим займемся, короткое шаг в сторону для исследования композиции протоколов.

Протоколы могут объединяться путем расположения 0 или более протоколов между угловыми скобками в предложении  protocol<> . Книга Apple Swift говорит следующее:

ЗАМЕЧАНИЕ
Композиция протоколов не определяет новый , постоянный тип протокола. А определяет временный локальный протокол,  у которого есть комбинированнык требования всех протоколов в композиции.

Читая это, можно подумать, что декларирование протокола protocol<P,Q> подобно декларированию анонимного протокола Tmp: P, Q { }, и Tmp можно использовать не давая ему имени. Но означает это не совсем то, и способ, который бы высветил разницу состоит в декларировании функций, которые имеют аргументы, декларированные с протоколом.

Continue reading

Какие функции вызывает Swift? Часть 2: Единственные аргументы.

Это русский перевод статьи airspeedvelocity 

Which function does Swift call? Part 2: Single Arguments

В предыдущей статье мы видели, что Swift разрешает “перегрузку” ( overloading ) функций просто по типу возвращаемого значения. С такого типа “перегрузками” явное объявление типа говорит Swift какую функцию вы хотите вызвать:

// r будет иметь тип Range<Int>
let r = 1...5

// если вы хотите тип ClosedInterval<Int>, вам следует
// явно указать:
let integer_interval: ClosedInterval = 1...5

Но все это не объясняет, почему мы получаем тип Range по умолчанию, хотя не указывали, какой тип возвращаемого значения мы хотим. Для ответа на этот вопрос нам следует посмотреть на аргументы функции. И мы начнем с простейших функций, у которых один аргумент.

В противоположность возвращаемым значениям, функции с теми же самыми именами, но с различными типами своих аргументов не всегда нуждаются в явной “однозначности” ( disambiguation). Swift будет пытаться их выбрать наилучшим образом, основываясь на различных критериях “наилучшего соответствия”.

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

Если Swift не находит функцию, которая имеет точно такой же тип, как мы передали при вызове, следующей предпочтительной опцией является наследуемый класс или протокол. Классы -“дети” или протоколы являются более предпочтительными чем “родители”.

Давайте посмотрим это в действии:

Continue reading

Какие функции вызывает Swift? Часть 1: Возвращаемые значения

Это русский перевод статьи airspeedvelocity

“Which function does Swift call? Part 1: Return Values “.

Тип данных ClosedInterval “стесняется”. Вам придется уговаривать его выйти из-за спины своего друга, Range.

// r будет иметь тип Range<Int>
let r = 1...5

// если вам нужен тип ClosedInterval<Int>, вам
// следует определить его явно:
let integer_interval: ClosedInterval = 1...5

// Но если вам нужен doubles, то нет необходимости
// декларировать его явно.
// floatingpoint_interval is a ClosedInterval<Double>
let floatingpoint_interval = 1.0...5.0

Начиная с  Swift 1.0 beta 5, Range поддерживается исключительно для представления диапазонов индексов в коллекции.

Если вы не работаете с индексами, тип ClosedInterval, возможно, это то, что вам нужно. У него есть методы, подобные contains, которые за фиксированное ( независящее от длины интервала ) время определяют, содержит ли интервал некоторое значение:

Continue reading

Пользовательский оператор управления потоками в Swift

Перевод статьи Custom Threading Operator in Swift.
Язык программирования Swift поддерживает пользовательские операторы, подобно перегрузке  операторов (operator overloading) в C++. Такие возможности языка программирования, как известно, позволяют “сверх активным” пользователям создавать “болото” из нечитаемого кода, поэтому я очень удивился, что эту возможность включили в Swift. Следует помнить, что перегрузка операторов, – это всего лишь более удобный способ вызова функций, поэтому не стоит увлекаться перегрузкой операторов. Однако, если их использовать сдержанно и с большой осторожностью, то определение новых операторов может дать элегантный и выразительный код с минимальными затруднениями  при чтении кода . В этой статье я показываю, как определить оператор, который упрощает переключение потоков, особенно при передаче выполнения из фонового  потока (background thread) в главный поток  (main thread) в iOS приложении.

Continue reading