Еще раз о string и NULL

 
В свое время на форуме уже поднимался вопрос о присвоении переменной тип string значения NULL ("Ошибка передачи NULL параметра в функцию"), но, к сожалению, в Help'e этот вопрос до сих пор никак не отражен, а описание некоторых функций прямо вводит в заблуждение программиста (особенно того, кто работал с C/C++)! Вот пример кода:
    tkt = OrderSend(symbol, cmd, volume, price, slippage, sl, tp, NULL, magic);


А вот другой код, который по всем канонам должен дать тот же результат:

    string s = NULL;
    tkt = OrderSend(symbol, cmd, volume, price, slippage, sl, tp, s, magic);


Однако в первом случае комментарий в созданном ордере будет пустым, а во втором он будет содержать цифру 0!

В связи с этим я вижу 2 варианта решения этой проблемы:

1. При присвоении типу string трактовать значение NULL как пустую строку. Это самое корректное и логичное, но может вызвать протесты тех, кто в своем коде каким-либо образом уже использует этот баг (а такая неоднозначность является именно багом)!

2. Доработать Help (этот вариант компромиссный, но более щадящий):
во-первых, в описании типа string указать, что присвоение переменым этого типа значения NULL записывает туда цифру 0, а не пустую строку (а лучше вообще запретить присвоение NULL переменным типа string на уровне компилятора, или хотя бы выдавать предупреждение при компиляции);
во-вторых, в описании всех функций, где в качестве значения параметра string приводится NULL, заменить его пустой строкой ("") и также добавить предупреждение об особенностях присвоения NULL переменным типа string (прямо запретить использование NULL здесь нельзя, т.к. огромное количество кода использует именно такой вариант).

P.S. А почему во встроенном редакторе MetaEditor нет возможности осуществить поиск / замену только внутри выделенного блока текста? Ведь эта функция есть во всех текстовых редакторах, кроме самых убогих, но MetaEditor под категорию «самых убогих» не попадает никоим образом! :)


 

А вот другой код, который по всем канонам должен дать тот же результат:


Это с каких пор неверная инициализация должна давать такой же результат ? Вы действительно программировали на С\С++ или только читали книжки ? В терминах С\С++ Вы пытаетесь воспользоваться неинициализированной и неразмещенной переменной. Если есть сомнения гляньте на описание типа MqlStr в примере. Чему Вы присваиваете значение NULL ? Был бы это Вами созданный класс - следовало бы перегрузить функцию инициализации для того, чтобы такая инициализация допускалась и работала правильно (как вариант: прегрузить операцию присвоения, задать "конструктор"). Если это не сделано, то операция некорректна.
Визуал сразу генерирует предупрежедения при использовании неинициализированных переменных.
Думаю, самым правильным будет генерировать ошибку на этапе компиляции.

Успехов.
 
—> Vladislav
Это с каких пор неверная инициализация должна давать такой же результат ? Вы действительно программировали на С\С++ или только читали книжки ? В терминах С\С++ Вы пытаетесь воспользоваться неинициализированной и неразмещенной переменной. Если есть сомнения гляньте на описание типа MqlStr в примере. Чему Вы присваиваете значение NULL ? Был бы это Вами созданный класс - следовало бы перегрузить функцию инициализации для того, чтобы такая инициализация допускалась и работала правильно (как вариант операцию присвоения). Если это не сделано, то операция некорректна.
Визуал сразу генерирует предупрежедения при использовании неинициализированных переменных.
Думаю, самым правильным будет генерировать ошибку на этапе компиляции.

Что имеется в виду под «неверной инициализацией», о каких классах в MQL идет речь, какой пример имеется в виду и что значит «перегрузить функцию инициализации»??? Единственное, что приведенный код следует воспринимать не как самодостаточный и исчерпывающий, а как фрагмент кода из тела функции, где ранее переменная tkt, естественно, определена как int и все прочие параметры, кроме текста комментария, также заблаговременно объявлены и инициализированы. Мне казалось, это очевидно. :(

А суть вопроса не в размещении, инициализации, области видимости и пр. (как раз фрагмент взят из тела реально работающего, а значит и успешно компилирующегося, советника, только имена большинства параметров приведены в соответствие с Help для большей наглядности), а в том, что от перемены мест слагаемых (места, где указывается значение NULL для параметра string) сумма (т.е. результат) меняется кардинальным образом, а компилятор МТ4 это пропускает без каких-либо возражений или предупреждений, и в Help'e, который в случае МТ4 является основным руководством для программиста, в тех местах, где описан тип string и использующая его стандартная функция (в данном случае OrderSend) нигде ничего об этом не сказано.
 
Так я же и говорю: правильно было бы генерировать ошибку на этапе компиляции. Иначе "компилятору" придется "догадываться", чего хотел программист сказать этой конструкцией. Там нет одонозначности: в типе стринг два поля и нужно задавать правила инициализации и присвоения. И разные программеры теоретически могут подразумевать разные вещи под одной и той же записью.
Как вариант можно, конечно же, создать правила инициализации и присвоения и описать все это в хэлпах. Только я сомневаюсь, что это будет сделано.

А то, что компилятор такие конструкции пропускает при отсутствии таких правил - это не есть "гуд", естественно.

Успехов.
ЗЫ


Что имеется в виду под «неверной инициализацией»,


string a = NULL;



Это.
Из хелпа : NULL имеет значение 0 ( а не "") и "Указывает пустое состояние строки", (а не равен "" - еще раз подчеркиваю) это разные вещи.


о каких классах в MQL идет речь, какой пример имеется в виду и что значит «перегрузить функцию инициализации»???

Не в МКЛ, а в С\С++.
Вы используете класс string, который не относится к базовым и стало быть определен разработчиками самостоятельно. Учитывая, что сам МТ написан на С\С++, то стало быть и по этим правилам.

struct MqlStr
  {
   int               len;
   char             *string;
  };


Речь шла об этом типе данных - это реализация МТ-шного типа string на С\С++. Как видите присвоение значения NULL не будет однозначным. И не показано как определены конструктор и операция присвоения.
Определение этих функций для созданного программистом типа и называется "перегрузить" функцию (операцию), создать конструктор (деструктор) класса.
Тем самым программист сообщает компилятору, что же подразумевается под тем или иным действием и какие действия с определенным типом данных считаются корректными.
Кстати, то, что Вы можете написать string a = "asbdf"; или присвоить одной строковой переменной значение другой в терминах С\С++ обозначает, что операция присвоения "перегружена" (читайте определена) для класса string.

Все это из С++.

Написал кратко потому, что из Вашего первого поста сделал вывод, что Вы хорошо знакомы с С\С++.



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



Не имеет значения. Речь об определении и инициализации переменной строкового типа.


Успехов.

 
Вот именно на это я и хотел обратить внимание разработчиков МТ4! Все-таки я надеюсь, что хотя бы в описание типа string они внесут предупреждение об особенностях присвоения значения NULL!

P.S. Кстати, вспомнил еще один вопрос к разработчикам. Мне нигде не попадалось предупреждение, что при вычислении сложного условия всегда вычисляются все его составляющие, даже если результат вычисления предыдущих компонентов однозначно определяет результат! Пример фрагмента кода:
if (f1() && f2()) f3(); //f1() и f(2) — функции, возвращающие значение bool


Даже если f1() вернет false, функция f2() все равно будет вызвана и выполнена!
Во многих современных компиляторах при настройках по умолчанию функция f2() в этом случае не вызывается, а в MQL для этого надо писать «многоступенчатый» if:

if (f1()) {
  if (f2()) f3(); //f1() и f(2) — функции, возвращающие значение bool
}




 
Много раз уже говорили, что NULL - это просто напросто макроподстановка цифры 0.

Если хотите неинициализированную строку так и не инициализируйте её ничем.
 
О, мои уточнения Slawa опередил .
Все равно,надеюсь, ответил подробнее :).

Успехов.
 
Slawa
Много раз уже говорили, что NULL - это просто напросто макроподстановка цифры 0.

Если хотите неинициализированную строку так и не инициализируйте её ничем.

Так скажите об этом ещё один раз — в Help'е, в описании типа string !
Я-то это уже понял, но только после того, как сам вляпался. :(

->Vladislav
Благодарю за разъяснения, но...
MQL позиционируется как самостоятельный язык, и потому, если я работаю в его рамках и не собираюсь экспортировать или импортировать данные, то я действую в соответствии с его правилами, которые для пользователей изложены недостаточно чётко в очень существенных моментах. И в этом случае мне безразлична внутренняя структура его данных (тем более что он не поддерживает доступ к ним через указатели), а также что было использовано при его создании — C++, Бейсик или Ассемблер! А тип string, как он описан в Help'е MQL, не подразумевает различия между пустой строкой и пустым указателем на строку, важные в C/C++ — если в MQL я создал переменную типа string, она уже есть, а ее значение следует считать неопределенным (не пустым, а именно неизвестно каким). Все остальные особенности и правила должны быть явно оговорены в описании соответствующего типа данных в Help'e MQL (возможно, в специальном разделе «Advanced»).
 
Здесь Вы совершенно правы и даже возразить нечего да и незачем - что нужно, то нужно.

Просто я считаю, что если учитывать несколько больше, чем описано разработчиками когда для этого есть возможности (в основном редко на какой продукт есть полные описания и здесь речь не только об МТ), это зачастую позволит сэкономить время на разработку приложений.


Успехов.