Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
V>>>Наоборот, переменная живет и рантайм. (кроме случаев оптимизации компилятором) V>>>Наверно ты имел ввиду, что символьное имя переменной в рантайм не живет? Но это не то же, что переменная. Просто символьный идентификатор в процессе компиляции (или линковки) заменяется некий конкретный вид адресации с некоторой фиксированной (обязательно!) составляющей. Вот эта фиксированная составляющая и отличает одну переменную от другой даже в рантайме. В этом плане мало что изменилось со времен переменных в ассемблере, разве что системы типов побогаче, чем в инструкциях db, dw, dd, dq. S>>То определение переменной, на которое ты ссылался, утверждает что переменная и есть символическое имя.
V>Я ссылался на определение, что переменная — это именованная область памяти, что есть тоже самое, что и алиас/синоним некоего представления (пусть числового) адреса этой области. Я просто обратил внимание, что имя-то в процессе компиляции/линковки уйдет, а область памяти — нет, будь оно хоть чем: глобальной областью, локальной или полем другого объекта.
Я не настаиваю на точности определения, но раз оно говорит что переменная — это именованная область памяти, а имени в рантайме нет, то значит согласно этому определению, в рантайме нет переменной.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>Возражаю. Тип *(int*) будет int. Усугубим. Возьмем int**, тип *(*(int**)) будет int, а не int&&, согласно твоей логике.
V>Дык, тип int& компилятором тоже воспринимается в выражениях как int, когда rvalue. Я же акцентировал выше. Если это r-value, то это int, даже если исходный тип был явно определенный int&, а если это l-value — то это семантика ссылочного типа, точно такая же, как у обычной ссылки. Помнишь я сетовал, что у обычного С семантика ссылок есть, это l-value, а самих сылок нет.
V>Вот нашел ссылку, подробно Павел когда-то расписал: http://www.rsdn.ru/forum/cpp/141873.1.aspx
За ссылку спасибо, но это ничего не доказывает в обсуждаемом предмете.
V>>>Дык, точно так же как и в случае любых других констант: не факт что занимает память когда в статике или локально, но обязательно занимает, когда является экземплярным мембером. Такие вот в С++ константы. S>>Адрес константы мы взять можем? А ссылки?
V>Косвенно разве что. V>Есть такой прием, называется — "оборачивание ссылок". Этот прием пользуется тем, что под ссылку-мембер всегда выделяют память, поэтому можно сделать структуру с одним полем — ссылкой, и оперировать этой структурой как обычным значением.
Косвенно и не для каждой ссылки
V>>>Значение может и на куче лежать, какие проблемы? Только это уже будет не константа времени компиляции, а константа времени выполнения. В любом случае, то, что ты написал, верно и для констант-указателей. S>>У константы-указателя можно взять адрес, не?
V>И? V>Ты опять сравниваешь список операций НАД переменными ссылочных типов, используя это как аргумент, когда утверждалось, что эти ссылочные типы практически идентичны по семантике, когда речь идет о доступе к целевому значению (т.е. того, на которые ссылается этот ссылочный тип). Так можно долго ходить по кругу, возражая, что холодильник прямоугольный, а вовсе не белый.
Так он ведь прямоугольный...
V>Ну конечно, если ссылочные типы разные, и то и разный набор операций над ними. Ссылка, в отличие от константного указателя, может иметь всего один уровень косвенности. Т.е. ссылка на ссылку невозможна. Если нам необходимы дополнительные уровни косвенности, то берем в таких сценариях указатели, какие проблемы?
никаких. V>На мой взгляд, отсутствие operator-> и невозможность взять адреса — абсолютно комплиментарны для ссылок, ведь определение operator-> искуственное и "натянутое" (синтаксиса ради), т.к. он возвращает указатель, к которому опять применяется operator->. Т.е. для встроенных указателей это был бы бесконечный рекурсивный вызов. А его нет. Это особый случай. Или наоборот, особым можно считать случай переопределенного operator-> у пользовательских типов, как угодно. Но это разные семантически вещи под одним синтаксисом, данным нам удобства ради. Так вот, будем рассматривать применение operator-> к ссылке. Например, ты можешь иметь ссылку и укзатель на тип, который, в свою очередь имеет operator->, например: V>
V>Т.е. мы просто убираем всю эту мишуру с разыменованием адреса для ссылки: V>(*tmpPtr)->XXX(), заменяя на более читабельное tmpRef->XXX();
V>Но ведь operator-> у ссылки не определен!
и что? V>Вот и все срослось. Ссылка — это синтаксический сахар над константным указателем, где разыменование адреса за нас делает ВСЕГДА делает компилятор. Т.е., обращаясь к ссылке, у нас обязательно идет разыменование ссылочного типа и оперирование целевым значением.
То что ссылка есть синтаксический сахар над константным указателем — возражать не будут. Но это не заставляет меня думать о ссылке как о переменной.
V>А раз так, то допустимая операция взятия адреса операция &tmpRef, после подстановки указателя будет выглядеть так: V>&(*ptrRef); V>Видишь, унарный operator& применяется не к самому ссылочному типу, а сразу к целевому, указуемому/ссылаемому полученному после разыменования. Итого, адрес у ссылки нельзя взять потому, что синтаксическая конструкция взятия адреса относится в случае ссылки к целевому объекту, а не к самой ссылочной переменной. Как и все остальные операторы, тот же operator->, который теперь относится к целевому объекту, а не ссылке. Круг замкнулся.
Замкнулся уже который раз, но ничего не изменилось в отношении того является ли ссылка переменной.
S>>По мне так мои предположения сходятся с реальным положением дел.
V>Не сходятся в случае ссылок как экземплярных полей.
Ссылка -экземплярное поле, ровно как и обычная ссылка, не хранит значение, на которое ссылается. Но хранит служебную информацию, позволяющую находить это значение, в точности как указатель. Однако, тип переменной указателя — указатель, и переменная указатель хранит свое значение (указатель). А ссылка — это сахар.
Здравствуйте, samius, Вы писали:
S>Я не знаю VB и VB.NET, но знаю что передача по ссылке в дотнете никак не связана с COM.
Таки связана. Где требуется COM interop и по сигнатуре идет указатель на структуру, там ты можешь передать ссылочный тип, либо же value-тип, но через модификатор ref, чтобы получить такой же уровень индирекции.
S>Я уже припух объяснять, что значение переменной типа указателя — есть указатель и он хранится в памяти, отведенной для переменной. Значение "переменной" типа ссылка хранится в другом месте, чем хранится внутреннее представление ссылки. При этом, нет возможности (легальной) взять адрес внутреннего представления ссылки и как-то повлиять на его содержимое.
Ну... Это пошла сугубо философия, не имеющая отношение к реально происходящему, в дебри которой я лезть всё равно не стану. Из того факта, что ты не можешь узнать устройство ссылки, ты делаешь слишком далекоидущие выводы. Меня, как программиста, вообще не должно интересовать ничего, кроме уровня косвенности в каждом конкретном случае, потому что косвенное обращение само по себе и есть основа гибкости и повторного использования одного и того же кода для разных экземпляров объектов/значений. И в этом плане, как управляемые ссылки дотнета (т.е. аналоги указателей С/С++), так и ссылки на мемберы или члены стека (т.е. аналоги ссылок в С++) демонстрируют одни и те же характеристики для программиста... Особенно, если не стоит задача узнать устройство ссылки... Важно лишь это — создание копии ссылки не есть создание копии целевого объекта/значения, и как следствие: несколько ссылок может ссылаться на один объект/значение, или же один и тот же аргумент-ссылка может ссылаться на разные объекты/значения в разных вызовах. А остальное непринципиально.
В общем, я такими вещами не заморачиваюсь и могу, разве что, опять отослать к способам адресации. Только так можно не заблудиться в "Философии". Потому как алгоритмы (просто алгоритмы, без привязки к языку) именно подразумевают некие способы адресации, т.е. нужно знать как эти алгоритмы переносить на C#, и понимать, что у нас есть свобода выбора: разместить объект в куче, например, или без проблем пользовать value-type, но передать его в аналогичную точку алгоритма по ссылке.
S>За ссылку спасибо, но это ничего не доказывает в обсуждаемом предмете.
Там расписана семантика l-value, которая в точности совпадает с семантикой ссылок. Вернись, насчет чего я там дал этот линк.
Например, здесь ссылки нет, а ссылочная семантика есть (вторая строка):
int i = 0;
i = 42;
V>>Есть такой прием, называется — "оборачивание ссылок". Этот прием пользуется тем, что под ссылку-мембер всегда выделяют память, поэтому можно сделать структуру с одним полем — ссылкой, и оперировать этой структурой как обычным значением. S>Косвенно и не для каждой ссылки
Для каждой. Важно, что я могу через этот прием безболезненно использовать такую завернутую ссылку там, где ранее использовал указатель, полностью повторив даже "побочную" семантику, в т.ч. взятия адреса этого объекта и мутации его значения.
S>То что ссылка есть синтаксический сахар над константным указателем — возражать не будут. Но это не заставляет меня думать о ссылке как о переменной.
А если она идет как параметр метода, то что это? Разве аргумент метода не является автоматически локальной переменной?
Да и это не принципиально. Важно, что мы можем создавать копии ссылок, вместо копий целевых объектов, и нам для создания таких копий не требуется знать внутреннее устройство ссылок. Отсюда потребность знать устройство ссылки близится к 0-лю. Для сравнени, я даже не припомню, чтобы хоть раз оперировать указателем именно как числовым значением, кроме случая отладочной информации, но! для ссылок в дебагере я могу получить ту же информацию, что и для указателей... оп-па.
В общем, тут высказался на этот счет, почему таки ссылки и указатели обеспечивают равную требуемую семантику (а ничего другого мне, программисту, и не надо): http://www.rsdn.ru/forum/philosophy/4516835.aspx
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>Я не знаю VB и VB.NET, но знаю что передача по ссылке в дотнете никак не связана с COM.
V>Таки связана. Где требуется COM interop и по сигнатуре идет указатель на структуру, там ты можешь передать ссылочный тип, либо же value-тип, но через модификатор ref, чтобы получить такой же уровень индирекции.
т.е. связана тем что ref и по ссылке можно передавать значения в COM? Ну так-то да, связана
S>>Я уже припух объяснять, что значение переменной типа указателя — есть указатель и он хранится в памяти, отведенной для переменной. Значение "переменной" типа ссылка хранится в другом месте, чем хранится внутреннее представление ссылки. При этом, нет возможности (легальной) взять адрес внутреннего представления ссылки и как-то повлиять на его содержимое.
V>Ну... Это пошла сугубо философия, не имеющая отношение к реально происходящему, в дебри которой я лезть всё равно не стану. Из того факта, что ты не можешь узнать устройство ссылки, ты делаешь слишком далекоидущие выводы.
Мне так не кажется V>Меня, как программиста, вообще не должно интересовать ничего, кроме уровня косвенности в каждом конкретном случае, потому что косвенное обращение само по себе и есть основа гибкости и повторного использования одного и того же кода для разных экземпляров объектов/значений. И в этом плане, как управляемые ссылки дотнета (т.е. аналоги указателей С/С++), так и ссылки на мемберы или члены стека (т.е. аналоги ссылок в С++) демонстрируют одни и те же характеристики для программиста... Особенно, если не стоит задача узнать устройство ссылки... Важно лишь это — создание копии ссылки не есть создание копии целевого объекта/значения, и как следствие: несколько ссылок может ссылаться на один объект/значение, или же один и тот же аргумент-ссылка может ссылаться на разные объекты/значения в разных вызовах. А остальное непринципиально.
Тот же уровень косвенности ничего не говорит о том, где переменная, а где нет.
V>В общем, я такими вещами не заморачиваюсь и могу, разве что, опять отослать к способам адресации. Только так можно не заблудиться в "Философии". Потому как алгоритмы (просто алгоритмы, без привязки к языку) именно подразумевают некие способы адресации, т.е. нужно знать как эти алгоритмы переносить на C#, и понимать, что у нас есть свобода выбора: разместить объект в куче, например, или без проблем пользовать value-type, но передать его в аналогичную точку алгоритма по ссылке.
Со своим пониманием где есть переменная, а где нет, я как-то не испытываю проблем с переносом алгоритмов на С# и не только.
S>>За ссылку спасибо, но это ничего не доказывает в обсуждаемом предмете.
V>Там расписана семантика l-value, которая в точности совпадает с семантикой ссылок. Вернись, насчет чего я там дал этот линк. V>Например, здесь ссылки нет, а ссылочная семантика есть (вторая строка): V>
V>int i = 0;
V>i = 42;
V>
Хорошо. Но здесь переменная есть и в точности одна, а ссылки нет, хоть и ссылочная семантика есть.
V>>>Есть такой прием, называется — "оборачивание ссылок". Этот прием пользуется тем, что под ссылку-мембер всегда выделяют память, поэтому можно сделать структуру с одним полем — ссылкой, и оперировать этой структурой как обычным значением. S>>Косвенно и не для каждой ссылки
V>Для каждой. Важно, что я могу через этот прием безболезненно использовать такую завернутую ссылку там, где ранее использовал указатель, полностью повторив даже "побочную" семантику, в т.ч. взятия адреса этого объекта и мутации его значения.
int i = 0;
int &i1 = i;
Покажи как взять адрес служебной информации для ссылки i1 с помощью оборачивания
S>>То что ссылка есть синтаксический сахар над константным указателем — возражать не будут. Но это не заставляет меня думать о ссылке как о переменной.
V>А если она идет как параметр метода, то что это? Разве аргумент метода не является автоматически локальной переменной?
Предпочитаю считать что переменная остается за бортом метода. V>Да и это не принципиально. Важно, что мы можем создавать копии ссылок, вместо копий целевых объектов, и нам для создания таких копий не требуется знать внутреннее устройство ссылок. Отсюда потребность знать устройство ссылки близится к 0-лю. Для сравнени, я даже не припомню, чтобы хоть раз оперировать указателем именно как числовым значением, кроме случая отладочной информации, но! для ссылок в дебагере я могу получить ту же информацию, что и для указателей... оп-па.
V>В общем, тут высказался на этот счет, почему таки ссылки и указатели обеспечивают равную требуемую семантику (а ничего другого мне, программисту, и не надо): http://www.rsdn.ru/forum/philosophy/4516835.aspx
V>>Таки связана. Где требуется COM interop и по сигнатуре идет указатель на структуру, там ты можешь передать ссылочный тип, либо же value-тип, но через модификатор ref, чтобы получить такой же уровень индирекции. S>т.е. связана тем что ref и по ссылке можно передавать значения в COM? Ну так-то да, связана
Не просто можно, а есть четкое соответствие, что в VB, что в VB.Net. Кстати, для стековых value-type даже маршаллинг не выполняется, прямо ссылка на них подается туда, где в COM ожидается указатель.
V>>В общем, я такими вещами не заморачиваюсь и могу, разве что, опять отослать к способам адресации. Только так можно не заблудиться в "Философии". Потому как алгоритмы (просто алгоритмы, без привязки к языку) именно подразумевают некие способы адресации, т.е. нужно знать как эти алгоритмы переносить на C#, и понимать, что у нас есть свобода выбора: разместить объект в куче, например, или без проблем пользовать value-type, но передать его в аналогичную точку алгоритма по ссылке. S>Со своим пониманием где есть переменная, а где нет, я как-то не испытываю проблем с переносом алгоритмов на С# и не только.
Ключевое было — взаимозаменяемость использования ссылочных типов, либо value-type для реализации алгоритмов.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
V>>>Таки связана. Где требуется COM interop и по сигнатуре идет указатель на структуру, там ты можешь передать ссылочный тип, либо же value-тип, но через модификатор ref, чтобы получить такой же уровень индирекции. S>>т.е. связана тем что ref и по ссылке можно передавать значения в COM? Ну так-то да, связана
V>Не просто можно, а есть четкое соответствие, что в VB, что в VB.Net. Кстати, для стековых value-type даже маршаллинг не выполняется, прямо ссылка на них подается туда, где в COM ожидается указатель.
Дык это характерно вообще для интеропа, а COM — это лишь частный случай.
V>>>В общем, я такими вещами не заморачиваюсь и могу, разве что, опять отослать к способам адресации. Только так можно не заблудиться в "Философии". Потому как алгоритмы (просто алгоритмы, без привязки к языку) именно подразумевают некие способы адресации, т.е. нужно знать как эти алгоритмы переносить на C#, и понимать, что у нас есть свобода выбора: разместить объект в куче, например, или без проблем пользовать value-type, но передать его в аналогичную точку алгоритма по ссылке. S>>Со своим пониманием где есть переменная, а где нет, я как-то не испытываю проблем с переносом алгоритмов на С# и не только.
V>Ключевое было — взаимозаменяемость использования ссылочных типов, либо value-type для реализации алгоритмов.
Взаимозаменяемости нет. Как только value передается по ссылке, говорить о передаче value неуместно.
Здравствуйте, samius, Вы писали:
V>>Не просто можно, а есть четкое соответствие, что в VB, что в VB.Net. Кстати, для стековых value-type даже маршаллинг не выполняется, прямо ссылка на них подается туда, где в COM ожидается указатель. S>Дык это характерно вообще для интеропа, а COM — это лишь частный случай.
Ну коль ты упомянул термин ByRef, то его ноги растут из VB, у которого объекты являются объектами COM, и я тебе напомнил про маппинг ByRef на указатели в COM. А так-то да, на дотнетный p-invoke это тоже распространяется.
S>>>Со своим пониманием где есть переменная, а где нет, я как-то не испытываю проблем с переносом алгоритмов на С# и не только.
V>>Ключевое было — взаимозаменяемость использования ссылочных типов, либо value-type для реализации алгоритмов. S>Взаимозаменяемости нет. Как только value передается по ссылке, говорить о передаче value неуместно.
Таки есть. Если алгоритм требует некий экземпляр объекта для мутирующих действий, то можно пользовать как ссылочный тип, так и value-тип, передаваемый по ref. Два этих способа взаимозаменямы, и позволяют рефакторить код в целях оптимизации. В С++ аналогично, сценарии доступа по ссылке и по указателю взаимозамеяемы. Иногда я типы аргументов методов в С++ меняю с указателя на ссылки или в обратном направлении. С какого перепугу они при этом должны перестать становиться переменными, или опять начинать ими быть — ты все-равно не объяснишь, это противоречит здравому смыслу.
Здравствуйте, samius, Вы писали:
V>>Я ссылался на определение, что переменная — это именованная область памяти, что есть тоже самое, что и алиас/синоним некоего представления (пусть числового) адреса этой области. Я просто обратил внимание, что имя-то в процессе компиляции/линковки уйдет, а область памяти — нет, будь оно хоть чем: глобальной областью, локальной или полем другого объекта. S>Я не настаиваю на точности определения, но раз оно говорит что переменная — это именованная область памяти, а имени в рантайме нет, то значит согласно этому определению, в рантайме нет переменной.
Если область памяти никуда не делась, то позволю себе думать, что переменная есть. И убедиться в этом легко, положив рядом с программой PDB-файл. А вот если в процессе компиляции переменная "ушла" стараниями оптимизатора, т.е. "ушла" некая область памяти, то только в этом случае переменной не будет в рантайм, в чем опять же можно убедиться, положив рядом тот же PDB: в этом случае исходному символическому имени не будет соответствовать никакая область памяти скомпилированной программы.
========
Да и вообще... Мы же в программе не над символьными именами действия совершаем, а именно над ячейками памяти, над переменными, конкретные экземпляры которых указываем через символьные алиасы.
Здравствуйте, samius, Вы писали:
V>>Там расписана семантика l-value, которая в точности совпадает с семантикой ссылок. Вернись, насчет чего я там дал этот линк. V>>Например, здесь ссылки нет, а ссылочная семантика есть (вторая строка): V>>
V>>int i = 0;
V>>i = 42;
V>>
S>Хорошо. Но здесь переменная есть и в точности одна, а ссылки нет, хоть и ссылочная семантика есть.
А что не так-то? l-value в примере является временным значением. А временное значение не является переменной, хотя может, в свою очередь, иметь любой тип. Т.е. тебя же не смущает, когда мы имеем временное значение типа-указателя? Т.е. переменной нет, а указатель таки есть. Почему для ссылки это не так?
static int i = 0;
static int & ref2i() { return i; }
static int * ptr2i() { return &i; }
ref2i() = 42;
*ptr2i() = 42;
В этом примере одна переменная, а для доступа к ней используется ссылка и указатель, хотя ни одна, ни другой не являются переменными, но являются временными значениями, возвращаемыми ф-ями. Я ведь привык думать, что если ф-ия не void, то она возвращает некоторое значение. Поэтому для меняя ссылка — это такое же обычное значение ссылочного типа.
В этом примере самая важная строка — последняя. Об эту строку спотыкаются многие начинающие С/С++ программисты. Разыменование указателя — это не есть непосредственная операция извлечения значения, т.е. в данном случае не есть извлечение значения типа int и формирование временного значения, куда мы потом будем пытаться присвоить 42. Разыменование указателя — это просто приведение типа выражения, а коль выражение используется как l-value, то здесь приведение указателя к ссылке. По факту, коль уровень косвенности у обоих выражений одинаков, они рожают одинаковый бинарный код.
V>>Для каждой. Важно, что я могу через этот прием безболезненно использовать такую завернутую ссылку там, где ранее использовал указатель, полностью повторив даже "побочную" семантику, в т.ч. взятия адреса этого объекта и мутации его значения. S>
S>int i = 0;
S>int &i1 = i;
S>
S>Покажи как взять адрес служебной информации для ссылки i1 с помощью оборачивания
Для этого ее надо разместить полем некоей структуры и оперировать этой структурой вместо ссылки:
int i = 0;
struct RefBox { int & ref; } iref = { i };
Для семантики мутирования надо вручную определить оператор присвоения и конструктор копирования. После этого можно пользовать структуру целиком в тех местах, где пользовался int*, с сохранением семантики взятия адреса и т.д. Осталось еще определить для этой структуры такой метод:
int * operator->() { return &ref; }
и можно будет пользовать вместо указателя даже без всякого рефакторинга, развязавшись только через typedef.
V>>А если она идет как параметр метода, то что это? Разве аргумент метода не является автоматически локальной переменной? S>Предпочитаю считать что переменная остается за бортом метода.
А в стеке что лежит при использовании соглашений вызова cdecl или pascal?
V>>Да и это не принципиально. Важно, что мы можем создавать копии ссылок, вместо копий целевых объектов, и нам для создания таких копий не требуется знать внутреннее устройство ссылок. Отсюда потребность знать устройство ссылки близится к 0-лю. Для сравнени, я даже не припомню, чтобы хоть раз оперировать указателем именно как числовым значением, кроме случая отладочной информации, но! для ссылок в дебагере я могу получить ту же информацию, что и для указателей... оп-па.
V>>В общем, тут высказался на этот счет, почему таки ссылки и указатели обеспечивают равную требуемую семантику (а ничего другого мне, программисту, и не надо): http://www.rsdn.ru/forum/philosophy/4516835.aspx
S>Ну так раз не надо, то позволь мне и дальше считать что ссылка и переменная — разные вещи.
Да позволю, разумеется, но не упустил ли ты выделенное? Я могу копировать/размножать ссылки. Делать их оч. много, даже занять ими всю доступную память. Никакого разрыва шаблона не происходит?
===========
ИМХО, рядом в ветке у нас идут разногласия насчет того, что есть переменная. Я пока не смог понять, что ты понимаешь под этим термином, похоже некую абстракцию, суть которой от меня всё еще ускользает. Вполне возможно, что именно тип ссылки каким-то образом запрещает переменной быть именно переменной в твоем понимании. Хотя, в начале поста я показал, что тип данных и переменная — не одно и то же, но коль есть некий тип, всегда можно создать переменную этого типа, даже в дотнете, начиная с 4-й версии .
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
V>>>Не просто можно, а есть четкое соответствие, что в VB, что в VB.Net. Кстати, для стековых value-type даже маршаллинг не выполняется, прямо ссылка на них подается туда, где в COM ожидается указатель. S>>Дык это характерно вообще для интеропа, а COM — это лишь частный случай.
V>Ну коль ты упомянул термин ByRef, то его ноги растут из VB, у которого объекты являются объектами COM, и я тебе напомнил про маппинг ByRef на указатели в COM. А так-то да, на дотнетный p-invoke это тоже распространяется.
Ноги термина-то может и растут, но сам ref к COM имеет лишь то отношение, что можно из safe C# подавать в методы структуры по ссылке. Ну и что интероп может взять реф ссылки и положить туда обертку над COM объектом, вернувшимся из метода через аут параметр.
V>>>Ключевое было — взаимозаменяемость использования ссылочных типов, либо value-type для реализации алгоритмов. S>>Взаимозаменяемости нет. Как только value передается по ссылке, говорить о передаче value неуместно.
V>Таки есть. Если алгоритм требует некий экземпляр объекта для мутирующих действий, то можно пользовать как ссылочный тип, так и value-тип, передаваемый по ref. Два этих способа взаимозаменямы, и позволяют рефакторить код в целях оптимизации.
Это не два разных способа, это один способ. value по ref — это ссылочный таки тип по спецификации. Я ошибся, когда утверждал что ссылочный тип это нечто другое. V>В С++ аналогично, сценарии доступа по ссылке и по указателю взаимозамеяемы. Иногда я типы аргументов методов в С++ меняю с указателя на ссылки или в обратном направлении. С какого перепугу они при этом должны перестать становиться переменными, или опять начинать ими быть — ты все-равно не объяснишь, это противоречит здравому смыслу.
Я пытался, но ты смотришь не на язык, а на стек, в то время как переменная — понятие языка а не стека и реализации.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>Я не настаиваю на точности определения, но раз оно говорит что переменная — это именованная область памяти, а имени в рантайме нет, то значит согласно этому определению, в рантайме нет переменной.
V>Если область памяти никуда не делась, то позволю себе думать, что переменная есть. И убедиться в этом легко, положив рядом с программой PDB-файл. А вот если в процессе компиляции переменная "ушла" стараниями оптимизатора, т.е. "ушла" некая область памяти, то только в этом случае переменной не будет в рантайм, в чем опять же можно убедиться, положив рядом тот же PDB: в этом случае исходному символическому имени не будет соответствовать никакая область памяти скомпилированной программы.
V>======== V>Да и вообще... Мы же в программе не над символьными именами действия совершаем, а именно над ячейками памяти, над переменными, конкретные экземпляры которых указываем через символьные алиасы.
Мы в программе совершаем действия над переменными. Но в рантайме у нас ячейки памяти. И PDB тут непричем. Он лишь соответствие (как ты и сказал) между ячейкой в рантайме и именем переменной в программе.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали: V>>>Например, здесь ссылки нет, а ссылочная семантика есть (вторая строка): V>>>
V>>>int i = 0;
V>>>i = 42;
V>>>
S>>Хорошо. Но здесь переменная есть и в точности одна, а ссылки нет, хоть и ссылочная семантика есть.
V>А что не так-то? l-value в примере является временным значением. А временное значение не является переменной, хотя может, в свою очередь, иметь любой тип. Т.е. тебя же не смущает, когда мы имеем временное значение типа-указателя? Т.е. переменной нет, а указатель таки есть. Почему для ссылки это не так?
Что-то я не понял. Какое еще временное значение? Здесь в качестве l-value выступает переменная i. Откуда указатели? Ты о примере выше, или который ниже?
V>
V>static int i = 0;
V>static int & ref2i() { return i; }
V>static int * ptr2i() { return &i; }
V>ref2i() = 42;
V>*ptr2i() = 42;
V>
V>В этом примере одна переменная, а для доступа к ней используется ссылка и указатель, хотя ни одна, ни другой не являются переменными, но являются временными значениями, возвращаемыми ф-ями. Я ведь привык думать, что если ф-ия не void, то она возвращает некоторое значение. Поэтому для меняя ссылка — это такое же обычное значение ссылочного типа.
Тут все верно. Переменная одна, и два временных значения. Одно временное значение ссылка, другое адрес. Хотя на стеке это может быть одним и тем же.
V>В этом примере самая важная строка — последняя. Об эту строку спотыкаются многие начинающие С/С++ программисты. Разыменование указателя — это не есть непосредственная операция извлечения значения, т.е. в данном случае не есть извлечение значения типа int и формирование временного значения, куда мы потом будем пытаться присвоить 42.
Да ладно? Я дал повод считать что я полагаю о том что разыменование извлекает значение? В таком случае бы следующий код не изменял бы значение i:
*&i = 42;
А я уже слишком давно знаком с C++ что бы не знать, что он делает. 20 лет в обед. V>Разыменование указателя — это просто приведение типа выражения, а коль выражение используется как l-value, то здесь приведение указателя к ссылке. По факту, коль уровень косвенности у обоих выражений одинаков, они рожают одинаковый бинарный код.
Разыменование это НЕ приведение типа выражения. Это переход от адреса к адресуемому месту в памяти.
А одинаковый бинарный код это не повод делать какие-то выводы в отношении используемых сущностей уровня языка.
S>>
S>>int i = 0;
S>>int &i1 = i;
S>>
S>>Покажи как взять адрес служебной информации для ссылки i1 с помощью оборачивания
V>Для этого ее надо разместить полем некоей структуры и оперировать этой структурой вместо ссылки: V>int i = 0; V>struct RefBox { int & ref; } iref = { i };
ты возьмешь адрес другой ссылки. Пусть служебная информация там будет та же, но ссылка-то другая. V>Для семантики мутирования надо вручную определить оператор присвоения и конструктор копирования. После этого можно пользовать структуру целиком в тех местах, где пользовался int*, с сохранением семантики взятия адреса и т.д. Осталось еще определить для этой структуры такой метод: V>int * operator->() { return &ref; } V>и можно будет пользовать вместо указателя даже без всякого рефакторинга, развязавшись только через typedef.
Это ничего не даст в споре о том, является ли ссылка переменной.
V>>>А если она идет как параметр метода, то что это? Разве аргумент метода не является автоматически локальной переменной? S>>Предпочитаю считать что переменная остается за бортом метода.
V>А в стеке что лежит при использовании соглашений вызова cdecl или pascal?
Ну вот, опять стек. В стеке будет лежать адрес.
V>>>Да и это не принципиально. Важно, что мы можем создавать копии ссылок, вместо копий целевых объектов, и нам для создания таких копий не требуется знать внутреннее устройство ссылок.
V>Да позволю, разумеется, но не упустил ли ты выделенное? Я могу копировать/размножать ссылки. Делать их оч. много, даже занять ими всю доступную память. Никакого разрыва шаблона не происходит?
Нет, не происходит. Я могу занять память чем угодно, это не будет означать что она занята переменными.
V>=========== V>ИМХО, рядом в ветке у нас идут разногласия насчет того, что есть переменная. Я пока не смог понять, что ты понимаешь под этим термином, похоже некую абстракцию, суть которой от меня всё еще ускользает. Вполне возможно, что именно тип ссылки каким-то образом запрещает переменной быть именно переменной в твоем понимании.
Я уже писал что ссылка представляет собой алиас того, на что она ссылается, в то время как указатель — это адрес, которым можно оперировать. Оперировать ссылкой нельзя, т.к. вместо нее операции будут происходить над местом, на которое ссылается ссылка.
V>Хотя, в начале поста я показал, что тип данных и переменная — не одно и то же, но коль есть некий тип, всегда можно создать переменную этого типа, даже в дотнете, начиная с 4-й версии .
Вот что интересно, будет ли корректной инструкция ldloc для "переменной" такого типа. Что будет являться ее результатом?
Здравствуйте, samius, Вы писали:
V>>А что не так-то? l-value в примере является временным значением. А временное значение не является переменной, хотя может, в свою очередь, иметь любой тип. Т.е. тебя же не смущает, когда мы имеем временное значение типа-указателя? Т.е. переменной нет, а указатель таки есть. Почему для ссылки это не так? S>Что-то я не понял. Какое еще временное значение? Здесь в качестве l-value выступает переменная i. Откуда указатели? Ты о примере выше, или который ниже?
Да о всё о том же, что l-value это не само значение, а классическая ссылка на него.
S>Тут все верно. Переменная одна, и два временных значения. Одно временное значение ссылка, другое адрес. Хотя на стеке это может быть одним и тем же.
Ну вот, ты уже согласился с тем, что ссылка — это тоже значение. ЧТД. Осталось ответить на вопрос, почему я могу иметь значение некоторого типа, а переменную этого типа создать не могу?
S>Разыменование это НЕ приведение типа выражения. Это переход от адреса к адресуемому месту в памяти.
Хм, ну это опять же вопрос сугубо точки зрения. При преобразовании типов в С++ в общем случае что-то происходит, вплоть до порождения новых объектов.
Разыменование — это добавление уровня индирекции, конечно тип меняется.
S>А одинаковый бинарный код это не повод делать какие-то выводы в отношении используемых сущностей уровня языка.
Ну коль язык это инструмент, то мне таки надо знать, что же этот инструмент делает.
V>>Для этого ее надо разместить полем некоей структуры и оперировать этой структурой вместо ссылки: V>>int i = 0; V>>struct RefBox { int & ref; } iref = { i }; S>ты возьмешь адрес другой ссылки. Пусть служебная информация там будет та же, но ссылка-то другая.
Да это не принципиально. Этот прием даже в бусте пользуют, когда надо хранить/копировать/передавать именно ссылку, а не указуемое значение. Главное здесь что — мы оперируем ссылкой, ссылающейся на всё тот же целевой объект, т.е. сохраняем единственно требуемую от ссылки семантику. Остальное никого не интересует.
S>Это ничего не даст в споре о том, является ли ссылка переменной.
Разве? С каких пор поле объекта перестало быть разновидностью переменной?
V>>>>А если она идет как параметр метода, то что это? Разве аргумент метода не является автоматически локальной переменной? S>>>Предпочитаю считать что переменная остается за бортом метода.
V>>А в стеке что лежит при использовании соглашений вызова cdecl или pascal? S>Ну вот, опять стек. В стеке будет лежать адрес.
В стеке будет лежать значение определенного типа, только это и важно. Я кажется начал догонять твой взгляд на вещи... да, в случае ссылки мы оперируем значением, которое расположено "где-то". Как и в случае указателей. Но это не есть ссылка именно на переменную. Ведь запросто можно сохранить ссылку на значение в куче, на которое больше никто не указывает, т.е. ни о какой другой переменной, кроме как об единственно ссылающейся это ссылке, речи быть не может. Поэтому даже с т.з. твоей логики, за бортом остается не переменная, а именно значение. Согласен? Ну а мой поинт лишь в том, что локальная переменная ссылочного типа на это значение ссылается.
V>>Да позволю, разумеется, но не упустил ли ты выделенное? Я могу копировать/размножать ссылки. Делать их оч. много, даже занять ими всю доступную память. Никакого разрыва шаблона не происходит? S>Нет, не происходит. Я могу занять память чем угодно, это не будет означать что она занята переменными.
Это если мы эту память потеряли насовсем, то да. А если связали в граф, то занята она таки самыми что ни на есть живыми переменными.
S>Я уже писал что ссылка представляет собой алиас того, на что она ссылается, в то время как указатель — это адрес, которым можно оперировать.
Ну и как можно оперировать константным адресом, с которым я сравнил ссылку? Распечатать его числовое представление для целей отладки?
V>>Хотя, в начале поста я показал, что тип данных и переменная — не одно и то же, но коль есть некий тип, всегда можно создать переменную этого типа, даже в дотнете, начиная с 4-й версии . S>Вот что интересно, будет ли корректной инструкция ldloc для "переменной" такого типа. Что будет являться ее результатом?
ldloc грузит само значение в стек, результатом будет копия значения ссылки на стеке.
Гораздо интереснее взять ldloca.
Здравствуйте, samius, Вы писали:
S>Я пытался, но ты смотришь не на язык, а на стек, в то время как переменная — понятие языка а не стека и реализации.
Э нет, переменная — это "инструкция" высокоуровневого ЯП. Программу мы пишем не для времени компиляции, а именно для рантайма. И переменная — это инструкция управления/распределения памяти, где само фактическое распределение выполняется опираясь на типы значений, которые необходимо разместить в некоей памяти. И не надо пытаться строить такую невинность, что это всё далекие абстракции, которыми мы оперируем и не интересуемся реально происходящим. Дудки. Ты именно всегда непосредственно указываешь для переменной область памяти, в которой ее необходимо распределить: будь то глобальная область памяти, локальная или в области памяти, занимаемой объектом (т.е. в виде поля другого типа). Абтрагирование от конкретики происходит только на уровне типов, т.е. мы абстрагируемся лишь от размеров памяти, требуемых для значений (и как побочный эффект — защищаемся от неверной интерпретации этой памяти), больше ни от чего. Остальное мы указываем очень даже конкретно из расчета как нам конкретно надо, чтобы оно работало в рантайм.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
V>>>А что не так-то? l-value в примере является временным значением. А временное значение не является переменной, хотя может, в свою очередь, иметь любой тип. Т.е. тебя же не смущает, когда мы имеем временное значение типа-указателя? Т.е. переменной нет, а указатель таки есть. Почему для ссылки это не так? S>>Что-то я не понял. Какое еще временное значение? Здесь в качестве l-value выступает переменная i. Откуда указатели? Ты о примере выше, или который ниже?
V>Да о всё о том же, что l-value это не само значение, а классическая ссылка на него.
l-value это все-таки место, а не ссылка. Сам же говорил, что в C нет ссылок
S>>Тут все верно. Переменная одна, и два временных значения. Одно временное значение ссылка, другое адрес. Хотя на стеке это может быть одним и тем же.
V>Ну вот, ты уже согласился с тем, что ссылка — это тоже значение. ЧТД. Осталось ответить на вопрос, почему я могу иметь значение некоторого типа, а переменную этого типа создать не могу?
Давай все-таки разграничивать о каких значениях мы говорим. Формально значением ссылки является то, на что она ссылается. Ты же говоришь о неком значении, которое является служебной информацией ссылки. Да, ты можешь создать переменную, которая будет содержать служебную информацию ссылки. Но значением ссылки будет не эта информация, а та, на которую она ссылается посредством этой служебной информации.
S>>Разыменование это НЕ приведение типа выражения. Это переход от адреса к адресуемому месту в памяти.
V>Хм, ну это опять же вопрос сугубо точки зрения. При преобразовании типов в С++ в общем случае что-то происходит, вплоть до порождения новых объектов.
А при разыменовании ничего не происходит. V>Разыменование — это добавление уровня индирекции, конечно тип меняется.
Тип меняется, но называть разыменование приведением типа — это лихо.
S>>А одинаковый бинарный код это не повод делать какие-то выводы в отношении используемых сущностей уровня языка.
V>Ну коль язык это инструмент, то мне таки надо знать, что же этот инструмент делает.
А делать инструмент может нечто значительно отличающееся от языковых терминов. Ты можешь находить некоторые соответствия, но делать по ним выводы о сущностях уровня языка в общем случае неверно.
S>>ты возьмешь адрес другой ссылки. Пусть служебная информация там будет та же, но ссылка-то другая.
V>Да это не принципиально. Этот прием даже в бусте пользуют, когда надо хранить/копировать/передавать именно ссылку, а не указуемое значение. Главное здесь что — мы оперируем ссылкой, ссылающейся на всё тот же целевой объект, т.е. сохраняем единственно требуемую от ссылки семантику. Остальное никого не интересует.
Мы не оперируем ссылкой, мы создаем новую ссылку каждый раз.
S>>Это ничего не даст в споре о том, является ли ссылка переменной.
V>Разве? С каких пор поле объекта перестало быть разновидностью переменной?
с тех пор, когда поле объекта стало ссылкой.
S>>Ну вот, опять стек. В стеке будет лежать адрес.
V>В стеке будет лежать значение определенного типа, только это и важно. Я кажется начал догонять твой взгляд на вещи... да, в случае ссылки мы оперируем значением, которое расположено "где-то". Как и в случае указателей. Но это не есть ссылка именно на переменную. Ведь запросто можно сохранить ссылку на значение в куче, на которое больше никто не указывает, т.е. ни о какой другой переменной, кроме как об единственно ссылающейся это ссылке, речи быть не может. Поэтому даже с т.з. твоей логики, за бортом остается не переменная, а именно значение. Согласен? Ну а мой поинт лишь в том, что локальная переменная ссылочного типа на это значение ссылается.
Я уже писал, что ссылка ссылается на место. Это место может быть переменной. А может быть местом в куче.
V>>>Да позволю, разумеется, но не упустил ли ты выделенное? Я могу копировать/размножать ссылки. Делать их оч. много, даже занять ими всю доступную память. Никакого разрыва шаблона не происходит? S>>Нет, не происходит. Я могу занять память чем угодно, это не будет означать что она занята переменными.
V>Это если мы эту память потеряли насовсем, то да. А если связали в граф, то занята она таки самыми что ни на есть живыми переменными.
Ты опять применяешь термин языка к рантайму. Представь что мы где-то в дебрях рекурсии без хвостовой оптимизации (пусть факториала). Стек кончился. Чем память забита? Да хрен, знает, а живая переменная лишь одна!
S>>Я уже писал что ссылка представляет собой алиас того, на что она ссылается, в то время как указатель — это адрес, которым можно оперировать.
V>Ну и как можно оперировать константным адресом, с которым я сравнил ссылку? Распечатать его числовое представление для целей отладки?
И это тоже. А еще можем взять адрес адреса и куда-нибудь передать.
V>>>Хотя, в начале поста я показал, что тип данных и переменная — не одно и то же, но коль есть некий тип, всегда можно создать переменную этого типа, даже в дотнете, начиная с 4-й версии . S>>Вот что интересно, будет ли корректной инструкция ldloc для "переменной" такого типа. Что будет являться ее результатом?
V>ldloc грузит само значение в стек, результатом будет копия значения ссылки на стеке.
Значение ссылки — это то место, на которое она ссылается. V>Гораздо интереснее взять ldloca.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>Я пытался, но ты смотришь не на язык, а на стек, в то время как переменная — понятие языка а не стека и реализации.
V>Э нет, переменная — это "инструкция" высокоуровневого ЯП. Программу мы пишем не для времени компиляции, а именно для рантайма. И переменная — это инструкция управления/распределения памяти, где само фактическое распределение выполняется опираясь на типы значений, которые необходимо разместить в некоей памяти. И не надо пытаться строить такую невинность, что это всё далекие абстракции, которыми мы оперируем и не интересуемся реально происходящим. Дудки. Ты именно всегда непосредственно указываешь для переменной область памяти, в которой ее необходимо распределить: будь то глобальная область памяти, локальная или в области памяти, занимаемой объектом (т.е. в виде поля другого типа). Абтрагирование от конкретики происходит только на уровне типов, т.е. мы абстрагируемся лишь от размеров памяти, требуемых для значений (и как побочный эффект — защищаемся от неверной интерпретации этой памяти), больше ни от чего. Остальное мы указываем очень даже конкретно из расчета как нам конкретно надо, чтобы оно работало в рантайм.
А тебя не смущает, что в рантайме может не оказаться того, что ты так старательно и конкретно указывал?
Здравствуйте, vdimas, Вы писали:
V>Э нет, переменная — это "инструкция" высокоуровневого ЯП. Программу мы пишем не для времени компиляции, а именно для рантайма. И переменная — это инструкция управления/распределения памяти, где само фактическое распределение выполняется опираясь на типы значений, которые необходимо разместить в некоей памяти. И не надо пытаться строить такую невинность, что это всё далекие абстракции, которыми мы оперируем и не интересуемся реально происходящим. Дудки. Ты именно всегда непосредственно указываешь для переменной область памяти, в которой ее необходимо распределить: будь то глобальная область памяти, локальная или в области памяти, занимаемой объектом (т.е. в виде поля другого типа). Абтрагирование от конкретики происходит только на уровне типов, т.е. мы абстрагируемся лишь от размеров памяти, требуемых для значений (и как побочный эффект — защищаемся от неверной интерпретации этой памяти), больше ни от чего. Остальное мы указываем очень даже конкретно из расчета как нам конкретно надо, чтобы оно работало в рантайм.
Это неконструктивная позиция.
Потому, что вот я указал очень конкретно, где что размещать:
public void Test()
{
int i = 42;
Где у нас i? В стеке?
Как бы не так! Потому что дальше (через 100 строк) я пишу:
Здравствуйте, samius, Вы писали:
V>>>>А что не так-то? l-value в примере является временным значением. А временное значение не является переменной, хотя может, в свою очередь, иметь любой тип. Т.е. тебя же не смущает, когда мы имеем временное значение типа-указателя? Т.е. переменной нет, а указатель таки есть. Почему для ссылки это не так? S>>>Что-то я не понял. Какое еще временное значение? Здесь в качестве l-value выступает переменная i. Откуда указатели? Ты о примере выше, или который ниже?
V>>Да о всё о том же, что l-value это не само значение, а классическая ссылка на него. S>l-value это все-таки место, а не ссылка. Сам же говорил, что в C нет ссылок
Ну так "место" — это и есть отсылка к значению, а не само значение.
Да, говорил, насчет С, что ссылок нет, а ссылочная семантика есть.
Помнишь, что l-value бывает не только во время присвоения по известному адресу, т.е. при присвоении значения переменной, но и вычисляемое? Поэтому не так всё просто с "местом".
V>>Ну вот, ты уже согласился с тем, что ссылка — это тоже значение. ЧТД. Осталось ответить на вопрос, почему я могу иметь значение некоторого типа, а переменную этого типа создать не могу? S>Давай все-таки разграничивать о каких значениях мы говорим. Формально значением ссылки является то, на что она ссылается. Ты же говоришь о неком значении, которое является служебной информацией ссылки. Да, ты можешь создать переменную, которая будет содержать служебную информацию ссылки. Но значением ссылки будет не эта информация, а та, на которую она ссылается посредством этой служебной информации.
Это будет "значением по ссылке", именно так его принято называть.
V>>Ну коль язык это инструмент, то мне таки надо знать, что же этот инструмент делает. S>А делать инструмент может нечто значительно отличающееся от языковых терминов. Ты можешь находить некоторые соответствия, но делать по ним выводы о сущностях уровня языка в общем случае неверно.
Не может, иначе инструмент станет негоден. Он должен что-то делать согласно спецификации. Причем, сама спецификация, в свою очередь, построена на основе общепринятой терминологии, а не какой-то специальной-абстрактной.
V>>Да это не принципиально. Этот прием даже в бусте пользуют, когда надо хранить/копировать/передавать именно ссылку, а не указуемое значение. Главное здесь что — мы оперируем ссылкой, ссылающейся на всё тот же целевой объект, т.е. сохраняем единственно требуемую от ссылки семантику. Остальное никого не интересует. S>Мы не оперируем ссылкой, мы создаем новую ссылку каждый раз.
Именно, только это от ссылки и требуется — при копировании их, не копировать целевое значение. Больше никакой семантической нагрузки они не несут.
V>>Разве? С каких пор поле объекта перестало быть разновидностью переменной? S>с тех пор, когда поле объекта стало ссылкой.
А что в этом случае страшное произошло? Память не из адреса объекта под ссылочную переменную выделилась или что-то еще?
S>Я уже писал, что ссылка ссылается на место. Это место может быть переменной. А может быть местом в куче.
Это ты первый раз в этом посте написал, до этого настаивал исключительно на переменной.
Так по-немногу и доберемся до цели.
V>>Это если мы эту память потеряли насовсем, то да. А если связали в граф, то занята она таки самыми что ни на есть живыми переменными. S>Ты опять применяешь термин языка к рантайму. Представь что мы где-то в дебрях рекурсии без хвостовой оптимизации (пусть факториала). Стек кончился. Чем память забита? Да хрен, знает, а живая переменная лишь одна!
Если в стеке нет временных переменных, а только адреса возвратов, то сложно не переделать в хвостовую рекурсию... А если там параметры — то они суть классические локальные переменные. "Язык рантайма" тут не при чем.
V>>Ну и как можно оперировать константным адресом, с которым я сравнил ссылку? Распечатать его числовое представление для целей отладки? S>И это тоже. А еще можем взять адрес адреса и куда-нибудь передать.
Внимание, вопрос! Зачем это надо для адреса, который константа? (с которым сравнили ссылку)
Серьезно, аж интересно стало.
V>>ldloc грузит само значение в стек, результатом будет копия значения ссылки на стеке. S>Значение ссылки — это то место, на которое она ссылается.
Это на ЯВУ, а в опкодах CLI — это адрес. После прочтения значения ссылки надо делать ldobj (или как там его)...