Индексация массивов.
От: Dufrenite Дания  
Дата: 28.08.07 14:18
Оценка:
Попытался индексировать массив типом uint:

module Program
{
    private Main() : void
    {
        def arr = array[1, 2, 3];
        def a = arr[1u];
    }
}


Получил странное сообщение об ошибке:
Error: expected System.UInt32, got int in array index: the types int and System.UInt32 are not compatible [simple unify]

Во первых, всё должно быть наоборот:
Error: expected System.Int32, got uint in array index: the types uint and System.Int32 are not compatible [simple unify]

И не понятно, почему нельзя индексировать массивы ничем кроме интов? Это создаёт действительно серьёзные проблемы при выводе типов.
Re: Индексация массивов.
От: Сергей Туленцев Россия http://software.tulentsev.com
Дата: 28.08.07 15:30
Оценка:
Здравствуйте, Dufrenite, Вы писали:

D>И не понятно, почему нельзя индексировать массивы ничем кроме интов? Это создаёт действительно серьёзные проблемы при выводе типов.


Баг. Недавно такая же штука с типом byte была. Починили. И эту починим.
--
Re[2]: Индексация массивов.
От: Dufrenite Дания  
Дата: 28.08.07 16:10
Оценка:
Здравствуйте, Сергей Туленцев, Вы писали:

СТ>Баг. Недавно такая же штука с типом byte была. Починили. И эту починим.


Понятно. Только там, наверное, надо со всеми целыми типами делать. Шарп вроде все поддерживает.
Re: Индексация массивов.
От: VladD2 Российская Империя www.nemerle.org
Дата: 29.08.07 11:06
Оценка:
Здравствуйте, Dufrenite, Вы писали:

uint > int, так что такое приведение не безопасно. Для констант, конечно, можно захардкодить преобразование, благо значение известно и его можно проверить во время компиляции. Но смысл этого от меня ускользает. В остальных же случаях я бы вообще предпочел бы видеть явное приведение типов. Так программист будет видеть, что возможно получение исключения в рантайме или некорректная работа программы в следствии переполенения.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Индексация массивов.
От: Константин Л. Франция  
Дата: 29.08.07 16:19
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, Dufrenite, Вы писали:


VD>uint > int, так что такое приведение не безопасно.


[]

Re[3]: Индексация массивов.
От: Блудов Павел Россия  
Дата: 30.08.07 05:20
Оценка:
Здравствуйте, Константин Л., Вы писали:

VD>>uint > int, так что такое приведение не безопасно.

КЛ>

Влад имеет ввиду, что при переходе через 2-х гигабайтную границу uint будет работать как ни в чём не бывало (что не безопасно), а int будет падать с overflow exception (если checked) или ArgumentOutOfRange (если без checked) что именно то, чего хотят все программисты.

Шутка. На самом деле массивы всегда индексировались и будет индексироваться именно знаковыми типами.
Причина банальна — IndexOf должен вернуть какое-то значение, если элемент не найден.

В Немерле/C#2.0 можно было бы возвращать Option[int]/int?, но в те времена, когда проектировался System.Array ничего этого не было, а теперь ИМХО, позно переделывать.
... << RSDN@Home 1.2.0 alpha rev. 726>>
Re[2]: Индексация массивов.
От: Dufrenite Дания  
Дата: 30.08.07 11:48
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>uint > int, так что такое приведение не безопасно.


В System.Array есть несколько перегруженных версий GetValue(), в частности Array.GetValue(Int64). Не вижу проблем с тем, чтобы воспользоваться этой версией функции, тем более, что преобразование uint -> long вполне корректно.
В этих рассуждениях есть только одно слабое место: преобразование ulong -> long, но компилятор C# разруливает эту ситуацию следующим образом:

    int i = arr[1UL];


    L_0014: ldc.i4.1 
    L_0015: conv.i8 
    L_0016: conv.ovf.i.un 
    L_0017: ldelem.i4


то есть делает безопасное преобразование. Не понимаю, зачем делать руками, когда можно поручить машине?
Re[3]: Индексация массивов.
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.08.07 11:54
Оценка:
Здравствуйте, Константин Л., Вы писали:

VD>>uint > int, так что такое приведение не безопасно.


КЛ>


using System.Console;

module Program
{
  Main() : void
  {
    def x = uint.MaxValue;
    def y = x :> int; // System.OverflowException was unhandled. Message: Arithmetic operation resulted in an overflow.

    WriteLine(y);
  }
}
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Индексация массивов.
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.08.07 13:58
Оценка:
Здравствуйте, Dufrenite, Вы писали:

D>Здравствуйте, VladD2, Вы писали:


VD>>uint > int, так что такое приведение не безопасно.


D>В System.Array есть несколько перегруженных версий GetValue(), в частности Array.GetValue(Int64). Не вижу проблем с тем, чтобы воспользоваться этой версией функции, тем более, что преобразование uint -> long вполне корректно.


GetValue — это катастрафически медренно.

D>В этих рассуждениях есть только одно слабое место: преобразование ulong -> long, но компилятор C# разруливает эту ситуацию следующим образом:


D>
D>    int i = arr[1UL];
D>


D>
D>    L_0014: ldc.i4.1 
D>    L_0015: conv.i8 
D>    L_0016: conv.ovf.i.un 
D>    L_0017: ldelem.i4 
D>


D>то есть делает безопасное преобразование. Не понимаю, зачем делать руками, когда можно поручить машине?


Что делать руками? Да и поведение компилятора C# завист от натсроек. В лучем случае будет рантайм-исключение. В худшем — некорректная работа. На мой взгляд оба варианта хуже чем разренешие неявных опасных преобразрований.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Индексация массивов.
От: Dufrenite Дания  
Дата: 30.08.07 21:08
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Что делать руками?


Лениво так делать:
matrix[row :> int, column :> int] = 123;


Хочется так:
matrix[row, column] = 123;


VD>Да и поведение компилятора C# завист от натсроек. В лучем случае будет рантайм-исключение. В худшем — некорректная работа. На мой взгляд оба варианта хуже чем разренешие неявных опасных преобразрований.


Хорошо, но если исключить случай опасных преобразований, то есть запретить индексацию типом ulong, то всё будет нормально работать. Для byte, sbyte, short и ushort делаем преобразование в int, что вполне допустимо. Для uint делаем преобразование в long, которым также вполне можно индексировать.
Re[4]: Индексация массивов.
От: mkizub Литва http://symade.tigris.org
Дата: 30.08.07 22:32
Оценка:
Здравствуйте, Блудов Павел, Вы писали:

БП>Здравствуйте, Константин Л., Вы писали:


БП>Влад имеет ввиду, что при переходе через 2-х гигабайтную границу uint будет работать как ни в чём не бывало (что не безопасно), а int будет падать с overflow exception (если checked) или ArgumentOutOfRange (если без checked) что именно то, чего хотят все программисты.


Проверка границ массива делается через ((unsigned)index) < array.length, а не index >= 0 && index < array.length, по той банальной причине, что первый вариант выполняется за одну инструкцию, а второй больше, чем за две. По этой же причине массивы не выйдут за 2х гигабайтный размер.

Пусть себе IndexOf возвращает signed int, какое он имеет отношение к доступу к элементу массива?
SOP & SymADE: http://symade.tigris.org , блог http://mkizub.livejournal.com
Re[5]: Индексация массивов.
От: VladD2 Российская Империя www.nemerle.org
Дата: 31.08.07 09:19
Оценка:
Здравствуйте, Dufrenite, Вы писали:

D>Лениво так делать:

D>
D>matrix[row :> int, column :> int] = 123;
D>

D>Хочется так:
D>
D>matrix[row, column] = 123;
D>


Так используй переменные подобающего типа и проблем не будет. Зачем же uint использовать? Они мало того, что больше, так еще и не CLS-совместимые.

D>Хорошо, но если исключить случай опасных преобразований, то есть запретить индексацию типом ulong, то всё будет нормально работать. Для byte, sbyte, short и ushort делаем преобразование в int, что вполне допустимо.


Дык как раз такую ошибку недавно и поправили. Так что теперь это должно работать.

D>Для uint делаем преобразование в long, которым также вполне можно индексировать.


Не совсем так. В Немерле пока что индексация через Int64 не поддерживается. А long == Int64. Но это тоже недоработка. Так что потенциально можно было бы сделать так. Только перед этим нужно сделать так чтобы компилятор поддерживал индексацию массивов long-ами. (вот только я ни разу в жизни не использовал эту возможность на прктике, ведь в 32-битных ОС это наверно и не работает)
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Индексация массивов.
От: Dufrenite Дания  
Дата: 31.08.07 15:03
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Так используй переменные подобающего типа и проблем не будет. Зачем же uint использовать? Они мало того, что больше, так еще и не CLS-совместимые.


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


public Действие(параметр : uint) : void
    requires параметр < МАКСИМАЛЬНОЕ_ЗНАЧЕНИЕ
    otherwise throw ArgumentException(
        "Невозможно выполнить действие: " +
        "параметр должен быть меньше максимального значения."
        )
{
}


предупреждая насмешки, скажу что уже неоднократно убеждался в преимуществах такого подхода. Однако суть в том, что если я буду использовать знаковый параметр, то мне придётся писать так:


public Действие(параметр : int) : void
    requires параметр < МАКСИМАЛЬНОЕ_ЗНАЧЕНИЕ
    otherwise throw ArgumentException(
        "Невозможно выполнить действие: " +
        "параметр должен быть меньше максимального значения."
        )
    requires param >= 0
    otherwise throw ArgumentException(
        "Невозможно выполнить действие: " +
        "параметр должен быть неотрицательным."
        )
{
}


не вижу смысла лишнюю работу делать.

VD>Не совсем так. В Немерле пока что индексация через Int64 не поддерживается. А long == Int64. Но это тоже недоработка. Так что потенциально можно было бы сделать так. Только перед этим нужно сделать так чтобы компилятор поддерживал индексацию массивов long-ами. (вот только я ни разу в жизни не использовал эту возможность на прктике, ведь в 32-битных ОС это наверно и не работает)


Наверное стоит добавить индексацию через long, как раз для исключения подобных проблем. Немерле очень хороший язык и его вполне можно использовать для промышленного программирования, надо только чтобы он не отставал хотя бы от того же пресловутого Шарпа даже в мелочах (хотя это конечно всего лишь моё личное мнение).
Re[7]: Индексация массивов.
От: rameel https://github.com/rsdn/CodeJam
Дата: 31.08.07 15:29
Оценка:
Здравствуйте, Dufrenite, Вы писали:

D>Однако суть в том, что если я буду использовать знаковый параметр, то мне придётся писать так:

D>

D>public Действие(параметр : int) : void
D>    requires параметр < МАКСИМАЛЬНОЕ_ЗНАЧЕНИЕ
D>    otherwise throw ArgumentException(
D>        "Невозможно выполнить действие: " +
D>        "параметр должен быть меньше максимального значения."
D>        )
D>    requires param >= 0
D>    otherwise throw ArgumentException(
D>        "Невозможно выполнить действие: " +
D>        "параметр должен быть неотрицательным."
D>        )
D>{
D>}
D>


D>не вижу смысла лишнюю работу делать.


Никакой лишней работы нет. Для описанного тобою случая есть ArgumentOutOfRangeException
... << RSDN@Home 1.2.0 alpha rev. 730 >>
Re[7]: Индексация массивов.
От: VladD2 Российская Империя www.nemerle.org
Дата: 05.09.07 10:22
Оценка:
Здравствуйте, Dufrenite, Вы писали:

D>Здравствуйте, VladD2, Вы писали:


VD>>Так используй переменные подобающего типа и проблем не будет. Зачем же uint использовать? Они мало того, что больше, так еще и не CLS-совместимые.


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


D>

D>public Действие(параметр : uint) : void
D>    requires параметр < МАКСИМАЛЬНОЕ_ЗНАЧЕНИЕ
D>    otherwise throw ArgumentException(
D>        "Невозможно выполнить действие: " +
D>        "параметр должен быть меньше максимального значения."
D>        )
D>{
D>}
D>


Ничего безопасного в этом код нет. Для плюсов такой код был бы максимально опасный, так как тот зарешает конвертацию int в unsigned.

D>предупреждая насмешки, скажу что уже неоднократно убеждался в преимуществах такого подхода. Однако суть в том, что если я буду использовать знаковый параметр, то мне придётся писать так:...


Я вообще не вижу нужды контролировать границы где попало. В большинстве случаев они проконтролируются в автомате, так как ты это число рано или поздно применишь для чего-то. Исключением являются публичные библиотеки и код использующий целые для хренения бастрактных идентификаторов.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: Индексация массивов.
От: Dufrenite Дания  
Дата: 05.09.07 16:33
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Я вообще не вижу нужды контролировать границы где попало.


Где попало конечно не надо, но я предпочитаю защищать, по возможности, все public методы.

VD>В большинстве случаев они проконтролируются в автомате, так как ты это число рано или поздно применишь для чего-то.


Может я и не прав, но мне хочется получать осмысленные сообщения об ошибках. По моему лучше если код вылетит с таким сообщением: "Невозможно выполнить действие: параметр должен быть меньше максимального значения.", чем с таким: "Index was outside the bounds of the array." В первом случае никаких вопросов не возникает, виноват сам: передал неверный параметр, во втором не понятно, то ли параметр не тот, то ли в вызываемом коде ошибка — надо лезть смотреть.
Однако же я не настаиваю — у каждого свой подход...

VD>Исключением являются публичные библиотеки и код использующий целые для хренения бастрактных идентификаторов.


Согласен. В этих случаях в обязательном порядке надо проверять.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.