Sub против функции без возвращаемого значения - PullRequest
0 голосов
/ 11 октября 2018

В чем смысл подпрограммы (Sub)?Почему бы не использовать Function без возвращаемого значения?


Редактировать

Что я имею в виду, почему существует ключевое слово Sub?Я могу использовать Function без объявления возвращаемого значения и иметь то же самое, нет?

Ответы [ 4 ]

0 голосов
/ 13 января 2019

Реальный вопрос, который нужно задать, заключается не в том, почему существует Sub, а в том, почему существует Function!Почему?

VBA построен поверх VB6, который полностью построен поверх COM.к сожалению, я не могу найти источник для этого, но все COM-методы должны возвращать HRESULT.Это означает, что все методы VBA / VB6 после компиляции являются подпрограммами!

Но если все методы являются подпрограммами, почему мой метод возвращает значение?Что ж, давайте рассмотрим пример ISynchronizeHandle::GetHandle:

HRESULT GetHandle(
  HANDLE *ph
);

Как видите, параметр для возвращаемого значения фактически предоставляется по ссылке в определении заголовка DLL C ++.По соглашению этот тип возврата всегда является последним параметром.Таким образом, для IStdMarshalInfo::GetClassForHandler определение:

HRESULT GetClassForHandler(
  DWORD dwDestContext,
  void  *pvDestContext,
  CLSID *pClsid
);

, где возвращаемый класс возвращается как CLSID класса (последний параметр).

Заголовок C ++ для Application.Evaluate() будет выглядеть примерно так:

HRESULT Evaluate(
     char[] sToEvaluate,
     char[] *sEvaluated
);

Это будет похоже на реализацию подпрограммы следующим образом:

Sub Evaluate(ByVal sToEvaluate as string, ByRef sEvaluated as string)

End Sub

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

Dim sRet as string
Evaluate("1+1",sRet)

Этот тип отстой ... Так что Microsoft решила "Эй, давайте дадим движку VB способ возвращать данные. Мы просто обернем существующее подчиненное поведение под капот, но наша виртуальная машина обработает реальный результат и вернет его функции пользователя ".Таким образом, вместо расширения существующего подчиненного поведения, они, вероятно, просто обернули поведение и создали новое объявление Function.

В конечном итоге Function было реализовано только как запоздалая мысль до Sub.Вот почему Sub существует с самого начала.


Помните, что вы можете, например, создать пользовательский класс VOID, а затем написать:

Function someFunction() as VOID

End Function

, а затемвызовите вашу функцию как:

Call someFunction()

Но это не рекомендуется.

0 голосов
/ 11 октября 2018

Я могу подумать о нескольких причинах из головы.

  • Он не позволяет вызывающей программе попытаться присвоить несуществующее возвращаемое значение чему-либо:

    Sub example()
        Dim x
        x = Foo     '<-- Potential runtime error.
        x = Bar     '<-- Compile error, Expected Function or variable.
    End Sub
    
    Function Foo()
    End Function
    
    Sub Bar()
    End Sub
    
  • В Excel это позволяет использовать его в качестве макроса (при условии, что у него нет аргументов).

  • Это менее эффективно, потому что оно имеетположить возвращаемое значение в стек.
  • Кто-то еще, кто читает код, не знает, что это за намерение.

    Function Foo()
        'Do some stuff
        'WTH is the return value not assigned?!
    End Function
    
  • Это (должен, предполагая в противном случае достойные методы кодирования) сигнализировать, что он не должен иметь побочных эффектов.У Sub ожидается, что будет иметь побочные эффекты.


Особенно в отношении редактирования.

Я могу использоватьФункция без объявления возвращаемого значения и одинаковая, нет?

Это неверный оператор.Если вы объявляете функцию, подобную этой ...

Function Foo()
    'Do some stuff
End Function

... , она по-прежнему имеет возвращаемое значение - она ​​просто неявная.Приведенный выше код в точности эквивалентен следующему:

Public Function Foo() As Variant
    'Do some stuff
End Function

VBA не заставляет вас явно объявлять тип возвращаемого значения (аналогично тому, как он не требует явного типа для оператора Dim).Это не значит, что у него его нет - он есть.

0 голосов
/ 11 октября 2018

Можно (не рекомендуется и не рекомендуется) использовать булевы функции вместо Sub s везде и убедиться, что они даже возвращают True, как только достигнут конец.

Вот так:

Public Function Main as Boolean
     'All the code here
     Main = True
End Function

Это легко проверить с помощью одной строки:

Debug.Print Main

Тогда вы можете использовать это так:

If Not SomeFunction Then IncrementLogString ("SomeFunction") И в конце вы можете проверить журнал со всеми ложными функциями.


Если честно, я делал это только один раз, около 5 лет назад, потому чтодругой разработчик настоял на этом, и у меня не было выбора.Что касается того факта, что это было, вероятно, самое большое приложение VBA, которое я когда-либо видел, и оно работало гладко (я не был основным разработчиком там, таким образом, не считая этого), я думаю, в этом нет никаких проблем.Через некоторое время я к этому привык, и было весело.Но, в общем, люди не одобрили бы это.

0 голосов
/ 11 октября 2018

Потому что это проясняет намерение .

A Function ясно говорит: "У меня будет кое-что для тебя, когда я вернусь". ожидание состоит в том, что Function возвращает что-то, , потому что именно для этого предназначены функции .

A Sub ясно говорит: "Я * 1014"* делая что-то , что вы должны ожидать, чтобы в конечном итоге добиться успеха ". ожидание состоит в том, что Sub выполняет действие, изменяет некоторое состояние, вызывает некоторые побочные эффекты.

A Function, который будет называться DoSomething, так же запутан, какSub с именем GetFoo: намерение скрыто, сама природа процедуры противоречит тому, как она рекламируется.Я ожидаю, что DoSomething либо преуспеет в , что-то делает , либо выдаст ошибку.Точно так же я ожидаю, что GetFoo, ну, принесет мне Foo.


Поскольку невозвратная функция не имеет смысла.

Внесколько языков программирования, Function (или семантически похожая конструкция), которая не возвращает значение во всех путях кода, даже не могут быть скомпилированы.Использование Функция-без-возврата-значения для всего в VBA очень похоже на злоупотребление языком только потому, что VBA не будет жаловаться на это.Как говорит нам обычная мудрость, не потому, что мы можем , мы должны .

Зачем возвращать void, когда вы можете вернуть bool везде,и не назначить его?

public bool DoSomething()
{
    // do stuff...
    // ...and don't assign the return value.
    // woopsie, doesn't compile.
}

Процедура VBA Sub похожа на метод C # void: она явно о ее невозвратной природе, и это хорошо.


Поскольку инструменты статического анализа кода будут жаловаться.

Компилятор VBA, как известно, не будет заботиться, если вы напишите код, в котором никогда не ясно, является ли невозвращение неявного возвращаемого значения намереннымили нет.

Когда вы делаете хотите вернуть значение - и забыть, потому что ошибки происходят постоянно - как вы можете быть уверены, что этот является законнымневозвратный, а тот другой нет?Без разбора кода и полного понимания всего, что он делает и почему , вы не можете сказать.Если вам повезет, вы смотрите на небольшие специализированные функции, которые, очевидно, выполняют одну задачу и делают это хорошо.В противном случае вам нужно тратить свое время на понимание происходящего, просто чтобы быть уверенным в что-то, что уже должно быть очевидным .

Инструменты статического анализа кода, такие как Rubberduck (Я утверждаю, что этот проект) помечает эти функции, поскольку они являются потенциальными ошибками , скрывающимися в вашей кодовой базе и ожидающими вас:

Rubberduck code inspection results

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