Страницы

Поиск по вопросам

Показаны сообщения с ярлыком const. Показать все сообщения
Показаны сообщения с ярлыком const. Показать все сообщения

пятница, 28 февраля 2020 г.

Dart: const и final в чем разница?

#const #dart #final


В чем разница и сходство в Dart'е const и final

Объясните для "чайника" пожалуйста
    


Ответы

Ответ 1



При использовании final - значение может быть присвоено один раз, но любое. При использовании const - накладываются ограничения на присваиваемое значение, оно должно быть доступно в момент компиляции. Так же const уже является final, однако в отличие от final значение не может быть изменено никаким образом. На пример: final a = [1,2,3]; a.add(112); print (a); // [1, 2, 3, 112] const b = [1,2,3]; b.add(111); // Uncaught exception: Unsupported operation: add print (b);

понедельник, 24 февраля 2020 г.

Binding color to constants class

#c_sharp #wpf #binding #color #const


Не могу прибиндить цветовую константу, которая находится в другой dll-ке.

"/>


Студия ругается на плохой код и  не хочет ничего делать. И принимает только объект,
а стринг не хочет. Как я понял, нужен конвертер.

Есть ли стандартный, или самому писать? (если можно, пример).
    


Ответы

Ответ 1



Ссылки на статические свойства нужно давать не через Binding, а через x:Static: При этом у вас, разумеется, должно быть правильно объявлено пространство имён constants, что-то вроде xmlns:constants="clr-namespace:Namespace.In.Assembly;assembly=Your.Assembly.Name" Не забудьте убедиться, что ваша сборка с константами называется Your.Assembly.Name, в ней в пространстве имён Namespace.In.Assembly находится public-класс ColorConstants, у которого есть статическое свойство (а не поле!) Black, у которого хотя бы getter объявлен как public. Для случая, когда ваш x:Static обладает неправильным типом (у вас строка, а ожидается Color), вам нужно применить конвертер. Самый простой синтаксически способ — написать свой MarkupExtension в замену x:Static, который заодно конвертировал бы значение в нужный тип стандартным конвертером. Итак: public class SmartStaticExtension : StaticExtension { public SmartStaticExtension(string member) : base(member) { } public override object ProvideValue(IServiceProvider serviceProvider) { // получим значение стандартного x:Static object value = base.ProvideValue(serviceProvider); // попытаемся вычислить тип, к которому надо привести IProvideValueTarget target = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget; if (target != null) { Type targetType = typeof(object); // если целевое свойство - DependencyProperty DependencyProperty dp = target.TargetProperty as DependencyProperty; if (dp != null) { targetType = dp.PropertyType; // берём тип у него } else { // целевое свойство - обыкновенное свойство, используем рефлексию PropertyInfo pi = target.TargetProperty as PropertyInfo; if (pi != null) targetType = pi.PropertyType; } // получаем стандартный конвертер: TypeConverter converter = TypeDescriptor.GetConverter(targetType); // и конвертируем value = converter.ConvertFrom(value); } return value; } } Имея такой конвертер, можно написать (разумеется, пространство имён local должно указывать туда, где определён SmartStaticExtension). Работает как со строками ("LightCyan") так и с RGB-константами ("#708090").

Php. Traits. Constants

#php #const #traits


Прошу совета толковых программистов.

Мне часто не хватает возможности (php 5.6) описывать в трейтах константы. Свойства
класса есть, а вот константы не ввели.

Собственно 2 вопроса.

Главный: Как правильно обеспечить множественное наследование с константами на уровне
самого php?

Интересует: Почему разработчики не дали возможность подмешивать в классы константы
с помощью трейтов? Может это плохая практика...

Дополнение: (многие не могут понять "А зачем?") Попробую показать.
Есть в БД много таблиц в которых есть поле status: 0 - выкл, 1 - вкл,
делаем трейт (зачем создавать таблицу для двух значений?)

trait Status
{
    const STATUS_INACTIVE = 0;
    const STATUS_ACTIVE = 1;

    public static function getStatuses()
    {
        return [
            static::STATUS_INACTIVE => 'Inactive',
            static::STATUS_ACTIVE => 'Active',
        ];
    }

    public function getStatusLabel($nullLabel = '')
    {
        $statuses = static::getStatuses();
        return isset($statuses[$this->status]) ? $statuses[$this->status] : $nullLabel;
    }
}


getStatuses() используем для выпадающего списка в форме, getStatusLabel() - тут я
думаю и так ясно. 
и это упрощенный пример.

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

Конечно я могу извратиться и сделать константы через статические свойства 

trait Status
{
    protected static $STATUS_INACTIVE = 0;
    public static function STATUS_INACTIVE() { return static::$STATUS_INACTIVE; }

    protected static $STATUS_ACTIVE = 1;
    public static function STATUS_ACTIVE() { return static::$STATUS_ACTIVE; }


но хотелось бы понять почему не дали трейтам константы
    


Ответы

Ответ 1



Трейты в php реализованы, как copy-paste на уровне интерпретатора. Не стоит ими злоупотреблять. Решение не позволять константы в трейтах мотивировано сложностью разрешения коллизий имён констант. Возможно, когда-нибудь эту проблему решат. А пока, ничто не мешает вам написать так: interface IActiveStatus { const STATUS_INACTIVE = 0; const STATUS_ACTIVE = 1; } trait Status { public static function getStatuses() { return [ static::STATUS_INACTIVE => 'Inactive', static::STATUS_ACTIVE => 'Active', ]; } public function getStatusLabel($nullLabel = '') { $statuses = static::getStatuses(); return isset($statuses[$this->status]) ? $statuses[$this->status] : $nullLabel; } } class A implements IActiveStatus { use Status; } или лучше: interface IActiveStatus { const STATUS_INACTIVE = 0; const STATUS_ACTIVE = 1; } trait Status { public static function getStatuses() { return [ IActiveStatus::STATUS_INACTIVE => 'Inactive', IActiveStatus::STATUS_ACTIVE => 'Active', ]; } public function getStatusLabel($nullLabel = '') { $statuses = static::getStatuses(); return isset($statuses[$this->status]) ? $statuses[$this->status] : $nullLabel; } } class A { use Status; } Хотя, я бы порекомендовал немножко пересмотреть интерфейс: trait Status{ protected $status = IActiveStatus::STATUS_INACTIVE; public function isActive() { return $this->status === IActiveStatus::STATUS_ACTIVE; } public function isInactive() { return $this->status === IActiveStatus::STATUS_INACTIVE; } public function setActive() { $this->status = IActiveStatus::STATUS_ACTIVE; } public function setInactive() { $this->status = IActiveStatus::STATUS_INACTIVE; } public function getStatusLabel() { return ([ IActiveStatus::STATUS_ACTIVE => 'Active', IActiveStatus::STATUS_INACTIVE => 'Inactive', ])[$this->status]; } }

Ответ 2



Можно не через трейты а через интерфейсы сделать. Отлично вписывается в множественное наследование interface IStatus { const STATUS_ENABLED = 1; const STATUS_DISABLED = 0; } interface IExtStatus { const STATUS_BLOCKED = 2; } class Test implements IStatus, IExtStatus { const STATUS_LOCAL = 3; } echo Test::STATUS_BLOCKED; echo Test::STATUS_LOCAL; echo Test::STATUS_ENABLED;

вторник, 18 февраля 2020 г.

C++11 range-based цикл

#cpp #foreach #const


В каких случаях использовать данный синтаксис? Где использовать const, а где ссылку?

for (const auto& elem: коллекция)
{  ...  }


Мои подозрения, если употребить const, то в elem будет храниться константный объект,
а если ссылку, то в elem будет храниться ссылка на константный объект. Если не употреблять
этого всего, то в elem будет хранится копия объекта.
    


Ответы

Ответ 1



const auto& если объект не будет меняться в теле цикла и/или оптимизация операций копирования. auto& если необходимо изменить объект в коллекции. auto если объект будет изменяться, но его копия в коллекции должна остаться неизменной.

воскресенье, 16 февраля 2020 г.

Php. Traits. Constants

#php #const #traits


Прошу совета толковых программистов.

Мне часто не хватает возможности (php 5.6) описывать в трейтах константы. Свойства
класса есть, а вот константы не ввели.

Собственно 2 вопроса.

Главный: Как правильно обеспечить множественное наследование с константами на уровне
самого php?

Интересует: Почему разработчики не дали возможность подмешивать в классы константы
с помощью трейтов? Может это плохая практика...

Дополнение: (многие не могут понять "А зачем?") Попробую показать.
Есть в БД много таблиц в которых есть поле status: 0 - выкл, 1 - вкл,
делаем трейт (зачем создавать таблицу для двух значений?)

trait Status
{
    const STATUS_INACTIVE = 0;
    const STATUS_ACTIVE = 1;

    public static function getStatuses()
    {
        return [
            static::STATUS_INACTIVE => 'Inactive',
            static::STATUS_ACTIVE => 'Active',
        ];
    }

    public function getStatusLabel($nullLabel = '')
    {
        $statuses = static::getStatuses();
        return isset($statuses[$this->status]) ? $statuses[$this->status] : $nullLabel;
    }
}


getStatuses() используем для выпадающего списка в форме, getStatusLabel() - тут я
думаю и так ясно. 
и это упрощенный пример.

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

Конечно я могу извратиться и сделать константы через статические свойства 

trait Status
{
    protected static $STATUS_INACTIVE = 0;
    public static function STATUS_INACTIVE() { return static::$STATUS_INACTIVE; }

    protected static $STATUS_ACTIVE = 1;
    public static function STATUS_ACTIVE() { return static::$STATUS_ACTIVE; }


но хотелось бы понять почему не дали трейтам константы
    


Ответы

Ответ 1



Трейты в php реализованы, как copy-paste на уровне интерпретатора. Не стоит ими злоупотреблять. Решение не позволять константы в трейтах мотивировано сложностью разрешения коллизий имён констант. Возможно, когда-нибудь эту проблему решат. А пока, ничто не мешает вам написать так: interface IActiveStatus { const STATUS_INACTIVE = 0; const STATUS_ACTIVE = 1; } trait Status { public static function getStatuses() { return [ static::STATUS_INACTIVE => 'Inactive', static::STATUS_ACTIVE => 'Active', ]; } public function getStatusLabel($nullLabel = '') { $statuses = static::getStatuses(); return isset($statuses[$this->status]) ? $statuses[$this->status] : $nullLabel; } } class A implements IActiveStatus { use Status; } или лучше: interface IActiveStatus { const STATUS_INACTIVE = 0; const STATUS_ACTIVE = 1; } trait Status { public static function getStatuses() { return [ IActiveStatus::STATUS_INACTIVE => 'Inactive', IActiveStatus::STATUS_ACTIVE => 'Active', ]; } public function getStatusLabel($nullLabel = '') { $statuses = static::getStatuses(); return isset($statuses[$this->status]) ? $statuses[$this->status] : $nullLabel; } } class A { use Status; } Хотя, я бы порекомендовал немножко пересмотреть интерфейс: trait Status{ protected $status = IActiveStatus::STATUS_INACTIVE; public function isActive() { return $this->status === IActiveStatus::STATUS_ACTIVE; } public function isInactive() { return $this->status === IActiveStatus::STATUS_INACTIVE; } public function setActive() { $this->status = IActiveStatus::STATUS_ACTIVE; } public function setInactive() { $this->status = IActiveStatus::STATUS_INACTIVE; } public function getStatusLabel() { return ([ IActiveStatus::STATUS_ACTIVE => 'Active', IActiveStatus::STATUS_INACTIVE => 'Inactive', ])[$this->status]; } }

Ответ 2



Можно не через трейты а через интерфейсы сделать. Отлично вписывается в множественное наследование interface IStatus { const STATUS_ENABLED = 1; const STATUS_DISABLED = 0; } interface IExtStatus { const STATUS_BLOCKED = 2; } class Test implements IStatus, IExtStatus { const STATUS_LOCAL = 3; } echo Test::STATUS_BLOCKED; echo Test::STATUS_LOCAL; echo Test::STATUS_ENABLED;

C++11 range-based цикл

#cpp #foreach #const


В каких случаях использовать данный синтаксис? Где использовать const, а где ссылку?

for (const auto& elem: коллекция)
{  ...  }


Мои подозрения, если употребить const, то в elem будет храниться константный объект,
а если ссылку, то в elem будет храниться ссылка на константный объект. Если не употреблять
этого всего, то в elem будет хранится копия объекта.
    


Ответы

Ответ 1



const auto& если объект не будет меняться в теле цикла и/или оптимизация операций копирования. auto& если необходимо изменить объект в коллекции. auto если объект будет изменяться, но его копия в коллекции должна остаться неизменной.

четверг, 13 февраля 2020 г.

Как хранятся глобальные const данные в библиотеках C++

#cpp #dll #lib #namespace #const


Есть статическая библиотека (.lib/.a).
В этой библиотеке находится файл с namespace, в котором две const переменные с публичным
и приватным ключом:

namespace dsa
{
   const std::vector private_key = {...}
   const std::vector public_key = {...}
}


Публичный ключ используется в динамической библиотеке (.dll/.so), путем подключения
исходной статической библиотеки.

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

Поскольку статическая библиотека является слепком .obj файлов единиц трансляции,
то оба ключа будут в ней, это понятно.

А вот будет ли в публичную динамическую библиотеку (.dll/.so) попадать информация
о приватном ключе, если в ней не вызываются функции, использующие его?

Как вообще организовано хранение подобных данных (глобальные const НЕ POD данные)
в windows/linux файлах динамических библиотек?
    


Ответы

Ответ 1



Да в *.dll попадут оба ключа. В этом отношении, линковка dll ни чем не отличается от exe. Проверить наличие переменной можно попросив линкер генерировать map файл. Линкер может выкинуть (при подключении .lib файла), только единицу трансляции целиком (соответствующею одному .obj/.cpp, из тех, что попали в .lib), и только в случае, если нет ссылок ни на один символ из этой единицы трансляции. Но ссылка на публичный ключ используется в любом случае... Самый надежный способ - написать две статические либы: с приватным и с публичным ключами по отдельности, тем более, что они должны обеспечивать разную функциональность: передача и прием сообщений.

Ответ 2



Исходя из ответа @Chorkov провел несколько тестов с использованием /MAP и результаты огорчили. Решил хранить приватный ключ в отдельном файле, исключив его таким образом из кода вообще.

воскресенье, 9 февраля 2020 г.

Пул констант в Java

#java #переменные #const #константа #pool


Не раз слышал о так называемом пуле констант в языке программирования Java. Знаю
о пуле объектов типа String, пуле для типов Byte, Short, Character, Integer, Long и
даже Boolean. Также знаю, что мы сами можем определять размер пула типа Integer, если
запускать приложение с параметром -Djava.lang.Integer.IntegerCache.high=XX, где XX
может колебаться в диапазоне от 127 до (Integer.MAX_VALUE - 129). Весь этот пул представляет
собой массив, каждое значение которого является элементом расположенным в порядке числового
возрастания и мы можем напрямую обратиться к нему по индексу за константное время O(1).
Я прекрасно понимаю, где хранится этот массив. У каждого целочисленного обёрточного
типа есть свой вложенный класс такого типа: 

private static class WrappingСlassNameCache {...}  


Где вместо WrappingСlassNameCache, мы подставляем конкретное имя класса, к примеру,
IntegerCache. 
Внутри это выглядит так: 

private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];

    static {
        // high value may be configured by property
        int h = 127;
        String integerCacheHighPropValue =
            sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            try {
                int i = parseInt(integerCacheHighPropValue);
                i = Math.max(i, 127);
                // Maximum array size is Integer.MAX_VALUE
                h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
            } catch( NumberFormatException nfe) {
                // If the property cannot be parsed into an int, ignore it.
            }
        }
        high = h;

        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);

        // range [-128, 127] must be interned (JLS7 5.1.7)
        assert IntegerCache.high >= 127;
    }


Ну Бог с ним, тут ничего мудрёного нет! А что же такое пул констант? Что он из себя
представляет? И вообще где хранятся все константы в Java? Если мы говорим о локальных
финализированных переменных, то они хранятся в стековой памяти. Если мы имеем дело
со static final полями, то эти поля хранятся в MetaSpace (раньше в PermGen), если мы
говорим о реализации JVM HotSpot. Так о каком вообще пуле может идти речь? Как всё
это реализовано? Описано в каком-то классе, который поставляется вместе со стандартным
API от Oracle (раньше Sun Microsystems) или же это нужно заглядывать в реализацию конкретной
JVM и читать JVMS? Подскажите, пожалуйста, надоело, что в которой раз сталкиваюсь с
этим понятием и никак не могу понять о чём идёт речь. Всем огромное спасибо за помощь! :)
    


Ответы

Ответ 1



У каждого класса свой пул констант. Чтобы понять для чего он нужен, разберём простой пример class Example { public void hello() { System.out.println("Hello"); } } Скомпилируем $ javac Example.java И заглянем внутрь $ javap -c -v Example.class public class Example minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #6.#14 // java/lang/Object."":()V #2 = Fieldref #15.#16 // java/lang/System.out:Ljava/io/PrintStream; #3 = String #17 // Hello #4 = Methodref #18.#19 // java/io/PrintStream.println:(Ljava/lang/String;)V #5 = Class #20 // Example #6 = Class #21 // java/lang/Object #7 = Utf8 #8 = Utf8 ()V #9 = Utf8 Code #10 = Utf8 LineNumberTable #11 = Utf8 hello #12 = Utf8 SourceFile #13 = Utf8 Example.java #14 = NameAndType #7:#8 // "":()V #15 = Class #22 // java/lang/System #16 = NameAndType #23:#24 // out:Ljava/io/PrintStream; #17 = Utf8 Hello #18 = Class #25 // java/io/PrintStream #19 = NameAndType #26:#27 // println:(Ljava/lang/String;)V #20 = Utf8 Example #21 = Utf8 java/lang/Object #22 = Utf8 java/lang/System #23 = Utf8 out #24 = Utf8 Ljava/io/PrintStream; #25 = Utf8 java/io/PrintStream #26 = Utf8 println #27 = Utf8 (Ljava/lang/String;)V { public Example(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."":()V 4: return LineNumberTable: line 1: 0 public void hello(); descriptor: ()V flags: ACC_PUBLIC Code: stack=2, locals=1, args_size=1 0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3 // String Hello 5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: return LineNumberTable: line 3: 0 line 4: 8 } Первое, что представляет интерес - это байткоды метода hello: 0: getstatic #2 3: ldc #3 5: invokevirtual #4 Цифры до двоеточия обозначают байт, с которого начинается байткод и его параметры. По шагу видно, что каждая операция - это два байта, один байт на код операции и один байт на параметр. Байткоды могут принимать только параметры фиксированного размера - integer, long, short, byte, character, float, double, reference. Чтобы передать в метод println строку "Hello", надо загрузить в стек ссылку на строку "Hello", а саму строку где-то сохранить. Вот это где-то как раз и есть пул констант. А символы #3 после байткода ldc - ссылка на 3-й элемент в пуле констант. Constant pool: #1 = Methodref #6.#14 // java/lang/Object."":()V #2 = Fieldref #15.#16 // java/lang/System.out:Ljava/io/PrintStream; #3 = String #17 // Hello #4 = Methodref #18.#19 // java/io/PrintStream.println:(Ljava/lang/String;)V Как можно увидеть из этого кусочка пула, его элементы сами часто ссылаются в пул. В частности наша строка под номером 3 ссылается на массив символов под номером 17. Если говорить о расположении пула констант в памяти JVM, то это один из участков MetaSpace.

пятница, 31 января 2020 г.

const vs CONST в чем разница?

#cpp #const


Когда писал метод в классе, заметил, что компилятор(VS 2015) распознает const и CONST
как разные идентификаторы, почему? Есть ли разница? Для чего переопределили const в CONST?

пример кода:

class A{

public:
void a(CONST int& val);//Будет ругаться, что метод не описан!
};

void A::a(const int& val){}

    


Ответы

Ответ 1



Дело в том, что в исходники часто рассчитаны на компиляцию как в режиме C, так и C++ (например, это так для заголовочных файлов WinAPI). Для этого можно объявить CONST макросом, который раскрывается в const при компиляции C++, и в пустую строку при компиляции C. Это часто используемый в реальности приём. Выдержка из свежего заголовочного файла WinAPI: #ifndef CONST #define CONST const #endif В вашем конкретно случае лучше не заморачиваться, и доопределить CONST: #define CONST const (ну или найти какой-нибудь заголовочный файл, в котором он есть). Ещё по теме: Зачем Microsoft в WinApi создает свои макросы для имеющихся в языке определений?

Ответ 2



Вообще-то C++ чувствителен к регистру, так что const - ключевое слово, а CONST - так, обычный идентификатор... const int CONST = 1; вполне компилируется :)

среда, 29 января 2020 г.

Изменение константной переменной

#cpp #указатели #const


в main() написал следующее

int const a=10;  
int *p=(int*)(&a);     
*p=20;  
cout<< a << endl;  
cout<< *p << endl;  
return 0;  


В отладчике наблюдаю изменение значения переменной "a" с 10 на 20. Но на экран выводится
10 и 20. То есть хоть и явно изменил константную переменную(знаю, что так нельзя делать,
просто протестил) на экран вывелось прежнее значение. Запускал под виндой и под ubuntu
на виртуалке. Почему же все-таки выводится 10 20, а не 20 20?
    


Ответы

Ответ 1



Компилятор видит, что a - это константа. Значит, она поменятся не может (он на это имеет право рассчитывать). Соответсвенно, когда он видит вывод переменной a - он имеет законное право подставить готовое известное значение. То есть, компилятор преобразует это в такое int const a=10; int *p=(int*)(&a); *p=20; cout<< 10 << endl; cout<< *p << endl; return 0; И сколько переменная не меняется, значение будет все равно выводиться не то, которое Вы ожидаете.

Ответ 2



Компилятор "знает", что a не меняется, поэтому и выводит первоначальное значение. Добавьте атрибут volatile (он говорит о том, что значение памяти может меняться независимо от создаваемого компилятором кода) и посмотрите: volatile int const a=10; int *p=(int*)(&a); *p=20; cout<< a << endl; cout<< *p << endl; return 0; теперь avp@wubu:hashcode$ g++ tt.cpp && ./a.out 20 20 avp@wubu:hashcode$

Ответ 3



C массивом прокатило без volatile. изменил и вывел изменённое значение const int arr[2][2]={{1,2},{3,4}}; int *p=(int *)((arr[1]+1)); cout<<"before"<

вторник, 31 декабря 2019 г.

Поместить static/const в интерфейс или абстрактный класс C#

#c_sharp #const #интерфейс


Как можно определить интерфейс или абстрактный класс, который вынудит реализовывать
публичную константу (отображаемое пользователям наименование класса, нужно вывести
список до того как юзверь тыкнет в заинтересовавший его класс) и статический метод
(например GetInstance)?
    


Ответы

Ответ 1



Никак. Это не поддерживается языком. Вы можете сэмулировать константу уровня экземпляра класса через свойство с одним лишь геттером: interface ISomething { string ClassName { get; } } Статические методы в интерфейс не вписываются никак, вообще. В текущей концепции вы получаете доступ к статическому объекту по имени класса, а не по экземпляру объекта. А поддержка интерфейсов реализована обычным образом, через таблицы виртуальных методов. Тем не менее, в будущих версиях языка возможны изменения, разрешающие схожую функциональность (generic-условия на наличие статического метода). Design team языка C# обсуждает эту возможность. Вот пример того, как динамически проверить наличие статического метода: interface ISomething { } static class SomethingChecker { public static Func CheckAndGetBuider() where T : ISomething { var type = typeof(T); var builder = type.GetMethod("GetInstance", BindingFlags.Public | BindingFlags.Static); // а есть ли такой метод? if (builder == null) throw new Exception(); // а не требует ли метод generic-аргумент? if (builder.IsGenericMethod) throw new Exception(); // а не требует ли метод параметров? if (builder.GetParameters().Length != 0) throw new Exception(); // а подходящий ли тип результата? if (!type.IsAssignableFrom(builder.ReturnType)) throw new Exception(); // все проверки пройдены return () => (T)builder.Invoke(null, null); } } Здесь рабочий пример использованием: http://ideone.com/bPyoEf

Ответ 2



На уровне языка это реализовать невозможно. Если вы хотите задать некое свойство для всего класса, то можно вместо статического свойства типа string завести статическое свойство типа IDictionary. Пусть каждый класс в статическом конструкторе записывает в словарь своё название. Если вы используете dependency injection, то подобное свойство можно добавить как мета-информацию к классу, например, с помощью атрибутов. Если при работе с этим классом всегда есть экземпляр, то можно добавить нестатическое свойство. В этом случае свойство не будет статическим, но смысл останется прежним. В целом, возможных реализаций много, и что вы выберете — зависит от вашей конкретной ситуации: как вы используете значение, когда и как создаются экземпляры и т.п.

воскресенье, 29 декабря 2019 г.

Что значит запись вида const { name } = value?

#javascript #const


Увидел в описании использования одного из npm-пакетов запись  вида const { NAME }
= value. В JavaScript не профи, так что никак не могу понять/найти зачем эти скобки
вокруг имени переменной и чем тогда это отличается от обычного const NAME = value?
    


Ответы

Ответ 1



Это называется деструктуризация, используется для более короткой записи const {name} = value; // value = {name: ''} name; // '' // то же самое что и const name = value.name; Можно использовать в параметрах функции const foo = ({prop}) => {} foo({prop: 'prop'}); Для возвращения нескольких параметров из функции const foo = () => ({var1: 1, var2: 2}) const {var1, var2} = foo(); Важно: имена переменных должны совпадать с ключами в объекте const {name} = {prop: 1}; // name = undefined // но если очень хочется:) const {prop: name} = {prop: 1}; // name = 1 Так же работает с массивами const [a, b] = [1, 2, 3, 4]; // a = 1, b = 2 Вот как теперь можно обменять значения двух переменных let a = 1, b = 0; [a, b] = [b, a];

Изменение констант через указатели в C vs C++

#cpp #c #указатели #const


Доброго времени суток.

В Си с помощью указателя я могу изменить значение константы.

const int a = 5;
int *p = &a;
*p = 10;
printf("%d", a);


Вывод:10

В Си++ компилятором допускается следующий код:

const int a = 5;
int *p = (int *) &a;
*p = 10;
std::cout << *p << " " << a;


Вывод:10 5

Значение по адресу указателя p изменилось, в то время как сама a - нет? Как это работает?
    


Ответы

Ответ 1



Ни в С, ни в С++ никаким способами не разрешается изменять значение константного объекта. Любые попытки такого изменения приводят к неопределенному поведению. Именно неопределенное поведение вы и наблюдаете в обоих своих примерах. Язык С 6.7.3 Type qualifiers 6 If an attempt is made to modify an object defined with a const-qualified type through use of an lvalue with non-const-qualified type, the behavior is undefined. Язык С++ 9.1.7.1 The cv-qualifiers 4 Except that any class member declared mutable can be modified, any attempt to modify a const object during its lifetime results in undefined behavior. В Си с помощью указателя я могу изменить значение константы. Нет, конечно. Такая инициализация указателя не допускается ни в С, ни в С++ const int a = 5; int *p = &a; Неявного преобразования const int * к int * в этих языках нет. Такое преобразование можно сделать только явно. Но и явное преобразование не поможет вам "изменить константу". Как это работает? Никак не работает. Неопределенное поведение.

суббота, 28 декабря 2019 г.

Зачем нужен const в сигнатуре функции?

#cpp #классы #функции #const


Например, у меня есть следующий код. 

#include     
using namespace std;  
class X {  
 int x;  
public:  
 X(int i = 2): x {i} {}  

 void print() const {cout << x;}  
 //           ^^^^^
 int getx() const {return x;} 
 //         ^^^^^
 X operator-(const X& rop) {return x + 2*rop.x;} 
 //          ^^^^^ 
 int operator-(int rop) {return 2*x + rop;}

}; 

int operator-(int lop, const X& rop) {
//                     ^^^^^
 return lop – rop.getx();
}  



int main() {  
 X x {6},y;  
 cout << x – 3 – y;  
 return 0;  
}  


Подскажите, пожалуйста, каково назначение ключевого слова const в сигнатуре функций?
    


Ответы

Ответ 1



Чтобы этот код мог работать с константными объектами. Это const означает, что вызов метода print() не изменит состояния объекта. void print() const {cout << x;} int getx() const {return x;} Здесь вы никак не меняете объект класса - поэтому нет никакого смысла делать НЕ const (мое мнение - лучше делать все, что только можно, с const, применяя его по умолчанию, и не использовать его только там, где это необходимо), зато эти методы можно будет вызвать, например, при передаче объекта в качестве константного параметра - вот как тут: X operator-(const X& rop) {return x + 2*rop.x;} Вы же никак не меняете rop, так что можете теперь вызывать оператор для любого объекта, в том числе временного. Кстати, операторы я бы тоже делал константными, типа X operator-(const X& rop) const {return x + 2*rop.x;} поскольку они никак не меняют состояние объекта.

Ответ 2



Нестатическая функция-член, помимо явно указанных в круглых скобках параметров, принимает еще и неявный указатель this. Т.е. указатель на экземпляр объекта, на котором эта функция была вызвана. Если const после списка параметров не указан this имеет тип X* const, т.е. указатель, который нельзя поменять, но сам объект изменять можно через этот указатель. А вот когда const присутствует, тип this становится const X* const, т.е. добавляется запрет на попытки изменить объект через этот указатель. Наличие const для конкретного параметра функции говорит о том, что нельзя изменять именно этот параметр. Для других параметров будут действовать их собственные ограничения. В общем случае, добавление const там, где объект не предполагается изменять позволяет писать более надёжный и понятный код, т.е. нельзя случайно изменить объект, который по логике разработчика меняться не должен. При попытке изменить такой объект, компилятор выдаст ошибку. По теме const можно напомнить ещё о существовании ключевого слова mutable, наличие которого у члена объекта позволяет менять этот член даже если была вызвана const функция объекта.

воскресенье, 22 декабря 2019 г.

CLion не воспринимает запись вида `T const& a` при описании функции

#cpp #clion #const #address #code_analyst


Есть некоторый класс Vector2 с перегруженным оператором (возможно аналогичное
поведение и с обычными ф-циями, но из-за непредсказуемого поведения (об этом позже)
достоверно проверить не удалось):

template 
class Vector2
{
    ...
    template  // объявляем дружественную ф-цию шаблонной
    friend Vector2 operator +(Vector2 const& l_v, Vector2 const& r_v);
    ...
}


Обращу внимание на форму записи константной ссылки - T const& a, а не const T& val.
Потом это будет играть важную роль.

Но при попытке описать эту ф-цию, а именно:

template 
Vector2 operator +(Vector2 const& l_v, Vector2 const& r_v)
{ ... }


начинается самое интересное, а именно абсолютно непредсказуемое поведение анализа
кода "на лету", от подобных генераций кода при попытке автоматической реализации объявленной
ф-ции:

template  Vector2 operator+(Vector2 < T >

const & l_v,

Vector2 const& r_v

)
{
return
Vector2();
}
// да-да, именно в таком виде, со всеми отступами


до категоричного отказа анализировать код, подчёркивая каждое второе слово красным
цветом.

В целом, иногда (очень редко), CLion воспринимает всё правильно, но через время снова
начинает деградировать.

А теперь к T const& a. Дело в том, что если поменять именно в описании ф-ции запись
на const T& a, то всё будет работать более чем нормально. Вид записи в объявлении ф-ции
никак не влияет.



Безусловно, можно было бы просто перейти на запись вида const T& a, да и код-то компилируется,
и это лишь визуальная помощь от данной IDE, но я бы не стал писать этот вопрос, если
бы не хотел решить эту проблему, поэтому хотелось бы понять, как это возможно сделать.



P.S.
CLion версии 2018.1, но также проверялось на 2018.1.6, на другом устройстве, где
результат был таким же.
    


Ответы

Ответ 1



Так как в функции и левый операнд и правый имеют тип класса, то такую функцию другом обьявить бессмысленно. Во вторых, если работа ыункции никак не связана с состоянием обьекта, и результатом функции является совершенно другой обьект, то вообше лучше избавить интерфейс класса от этой функции и определить ее отдельно (но в одном модуле). Например: class Integer { int k; public: Integer(int n = 0) : k(n){} //модификаторы //т.е. мы изменяем состояние обьекта *this Integer& operator +=(const Integer& r_v) { k += r_v.k; return *this; } //... //селекторы int get_data() const { return k; } // функция выдает состояние обьекта }; // operator+ (и подобные методы) определяем вне класса inline Integer operator +(const Integer& l_v, const Integer& r_v) { Integer t(l_v); t += r_v; return t; } Такой подход избавляет класс от лишнего интерфейса и наиболее логичен. И если этот подход применить в написании вашего класса, то все становится гораздо проще... template class Vector2 { //... public: Vector2& operator +=(Vector2 const& r_v); }; template inline Vector2 operator +(Vector2 const& l_v, Vector2 const& r_v) {...}

Ответ 2



Дружественной вы объявили какую-то странную функцию template friend Vector2 operator +(Vector2 const& l_v, Vector2 const& r_v); У этой функции есть неименованный шаблонный параметр, который нигде не используется в сигнатуре функции. Т.е. вы объявили template friend Vector2 operator +(Vector2 const& l_v, Vector2 const& r_v); (я просто дал имя U вашему безымянному параметру). При этом, например, для класса Vector2 другом будет template friend Vector2 operator +(Vector2 const& l_v, Vector2 const& r_v); Зачем вы ввели этот ненужный параметр - не ясно. К функции, определенной вами ниже template Vector2 operator +(Vector2 const& l_v, Vector2 const& r_v) { ... } ваше объявление никакого отношения не имеет. Здесь у вас параметр шаблона прямо влияет на сигнатуру функции. Это определение другом вашего класса не является. Это мешанина, наверное, и сбивает с толку анализатор кода. А теперь к T const& a. Дело в том, что если поменять именно в описании ф-ции запись на const T& a, то всё будет работать более чем нормально. Нет. Ничего работать нормально не будет. Как я сказал выше, ваша функция другом класса не является, со всеми вытекающими последствиями. О том, как правильно объявлять шаблонных друзей, тут уже не раз писалось Перегрузка шаблонных операторов с разделением на описание и имплементацию Доступ к привату через friend Ссылка на неразрешенный внешний элемент Вы, по-видимому, пытались реализовать именно template class Vector2 { ... template // объявляем дружественную ф-цию шаблонной friend Vector2 operator +(Vector2 const& l_v, Vector2 const& r_v); ... }; но почему вы решили, что этот вариант можно "сократить" до вашего - не ясно. Также вы можете обойтись вообще без дополнительной шаблонности вашего оператора, но при этом его придется определять прямо в классе template class Vector2 { ... friend Vector2 operator +(Vector2 const& l_v, Vector2 const& r_v) { // Определение придется писать прямо сюда } ... }; ибо С++ не предоставляет синтаксиса для определения такого оператора за пределами класса.

суббота, 21 декабря 2019 г.

Получение значение литерала (константы) средствами CIL

#net #const #cil


Скажем, у нас есть некая константа в откомпилированной сборке. Возьмем примера ради
класс Math из mscorlib.dll и константу Math.PI

Если посмотреть исходник в виде IL-кода, то мы увидим такое вот объявление поля:

.field public static literal float64 PI = float64(3.1415926535897931)


То есть по сути, PI является публичным статическим полем, помеченным как литерал
И именно из-за последнего не будет работать инструкция ldsfld в отношении Math.PI

Из-за чего следующий код не будет работоспособным:

.method public static float64 GetPi() cil managed
{
    .maxstack 1
    ldsfld float64 [mscorlib]System.Math::PI
    ret
}


При вызове GetPi() мы получим ошибку времени исполнения:


  System.MissingFieldException: "Поле не найдено: "System.Math.PI"."


В связи с чем у меня и возник вопрос: можно ли вообще средствами CIL вытащить значение
литерала из сборки и, если да, то как это сделать?



P.S. - я прекрасно понимаю, что при создании IL-кода из инструкций на, скажем, C#
значения констант подставляются сразу, так что сие:

return a * Math.PI;


будет преобразовано в:

ldloc a
ldc.r8 3.1415926535897931
mul
ret


Однако все таки стало интересно, есть ли в CIL инструкция, которая все таки извлекала
бы значение константного поля
    


Ответы

Ответ 1



В спецификации CIL достаточно четко указано: I.8.6.1.2 Location signatures The literal constraint promises that the value of the location is actually a fixed value of a built-in type. The value is specified as part of the constraint. Compilers are required to replace all references to the location with its value, and the VES therefore need not allocate space for the location. This constraint, while logically applicable to any location, shall only be placed on static fields of compound types. Fields that are so marked are not permitted to be referenced from CIL (they shall be in-lined to their constant value at compile time), but are available using reflection and tools that directly deal with the metadata. Выделенный кусок Fields that are so marked are not permitted to be referenced from CIL Поля отмеченные таким способом не могут быть доступны из CIL Так что нет, такой инструкции в CIL нет. Однако, как указано в том же пункте: but are available using reflection and tools that directly deal with the metadata. но доступны при использовании рефлексии или инструментов работающих напрямую с метаданными. перевод ответа на вопрос CIL - How do I use a public static literal field?

Ответ 2



Дополню ответ @Grundy: Как уже было сказано, штатными средствами CIL получить значение литерала нельзя, так что следует использовать рефлексию Собственно, этим и займемся) Получился такой вот generic-метод: .method public static !!ConstType GetConst(class [mscorlib]System.Type, string) cil managed { .maxstack 3 ldarg.0 // Кладем на стек тип, из которого будем тащить константу ldarg.1 // Кладем на стек название литерала ldc.i4 56 // Кладем на стек значение BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic // т.к. константа всегда является полем статичным и не совсем обязательно публичным) // Достанем FieldInfo callvirt instance class [mscorlib]System.Reflection.FieldInfo [mscorlib]System.Type::GetField(string, valuetype [mscorlib]System.Reflection.BindingFlags) ldnull // Получим его значение callvirt instance object [mscorlib]System.Reflection.FieldInfo::GetValue(object) // Распакуем unbox.any !!ConstType // Вернем ret } Тогда метод GetPi() можно переписать так: .method public static float64 GetPi() cil managed { .maxstack 2 // Получим тип класса System.Math ldtoken [mscorlib]System.Math call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) // Укажем, какую константу хотим из него вытащить ldstr "PI" // И, собственно, вытащим) call !!0 ILConsole.Program::GetConst(class [mscorlib]System.Type, string) ret } Теперь вызов метода не упадет в runtime, а вернет ожидаемое значение System.Math.PI) Еще раз подчеркну, что константы на то и константы, что их неизменяемое значение подставляется сразу в IL-код, так что при написании какого-нибудь компилятора не стоит использовать код выше, а следует просто вручную записать нужную величину куда следует Данный ответ приведен только в, так скажем, образовательных целях)

четверг, 12 декабря 2019 г.

В чем смысл типа char * const* в языке Си?

#c #указатели #const


char* - указатель на переменную типа char.

char* const - константный указатель.

const char* - указатель на константную переменную.

const char* const - константный указатель на константу.

char const* - тоже самое, что и const char*. Автоматически в него преобразуется.

Но про char* const* компилятор gcc(c99) рассуждает, как об отдельном типе. Тоже самое
с const char* const*. В чем заключается смысл * после const вкупе с char*? Как описать
этот тип?
    


Ответы

Ответ 1



Это такой же указатель на указатель, как char**, только менять его адрес (того указателя, на который указывает переменная) нельзя. char* pc1 = (char*)malloc(LENGTH); strcpy(pc1, "Hello"); char* pc2 = (char*)malloc(LENGTH); strcpy(pc2, "World"); char* const* ppc1 = &pc1; // OK *ppc1 = pc2; // compile-time error char** ppc2 = &pc1; // OK *ppc2 = pc2; // OK

Ответ 2



Расшифровывать подобные обозначения (и более суровые, с участием указателей на функции, например) порой сильно помогает ресурс cdecl char* const* x declare x as pointer to const pointer to char x это указатель на константный указатель на char — ссылка x (char* const*) менять можно. *x (char* const) менять нельзя. **x (char) менять можно.

Ответ 3



Цитата из книги Бена Клеменса "Язык С в XXI веке" (Глава 8, Ключевое слово const): Объявления следует читать справа налево. Таким образом: int const - константное целое; int const * - (неконстантный) указатель на константное целое; int * const - константный указатель на (неконстантное) целое; int * const * - указатель на константный указатель на целое; int const * * - указатель на указатель на константное целое; int const * const * - указатель на константный указатель на константное целое. Как видите, квалификатор const всегда относится к тому, что находится слева от него, - как и *. Можно переставить местами имя типа и const, то есть int const и const int - одно и то же (хотя проделать этот фокус с const и * не удастся). Я предпочитаю форму int const, потому что она согласуется с более сложными конструкциями и прави­лом чтения справа налево. Но чаще встречается форма const int, быть может, по­тому что её проще произнести на обычном языке (константное целое) или потому что так "всегда делали". Так или иначе, годятся оба варианта. В статье на хабре Так вы думаете, что знаете Const? пошли ещё дальше и добавили третий квалификатор const: int const * const * const - константный указатель на константный указатель на константное целое.

вторник, 10 декабря 2019 г.

Недопонимание с const

#c #указатели #const


Допустим, я создаю в main() массив указателей, под которые позже выделяю память и
инициализирую посредством функции fgets(). 

int main(void){    
    char *p[5];
    ............
   /* инициализация */
}


Затем я хочу отсортировать данный массив указателей и вызываю функцию sorting().
Для того, чтобы случайно не изменить данные в массиве указателей, аргумент функции
sorting я сделаю const, тобишь: 

void sorting(const char **p){
/* функция сортировки указателей */
}


Однако при вызове данной функции из main(), я получаю ошибку

int main(void){
.............
.............
sorting(p); 

}


предупреждение:


  passing argument 1 of ‘sorting’ from incompatible pointer type [-Wincompatible-pointer-types]
     sorting(p);
  expected ‘const char **’ but argument is of type ‘char **’
  void sorting(const char **p){


Насколько мне известно, то const значения можно инициализировать НЕ const значениями,
но это я читал для просто указателей. Скажите, пожалуйста, как решить данную проблему?
    


Ответы

Ответ 1



Ваше желание вполне понятно и естественно, но тем не менее в С не разрешено неявное приведение типа от char ** к const char **. На первый взгляд вам кажется, что вы просто запрещаете модификацию строк, но вместе с этим вы открываете другую "дыру" в защите константой корректности: если бы это было возможно, то внутри вашей функции sorting вы могли бы спокойно сделать, например p[0] = <адрес какого-то константного объекта типа char>; // Например: // static const char s[] = "Hello World!"; // p[0] = s; что привело бы к тому, что p[0] в main (имеющее тип char *) стало бы указывать на константный объект. И вы этого добились бы без применения явного приведения типа (!). Вот для того, чтобы не открывать такой дыры в защите, С не разрешает неявных преобразований T ** -> const T **. Красивого решения тут навскидку не придумаешь... В main вам, допустим, нужен именно char *[], а в sorting вы, допустим, хотите получать именно const char *[]. В такой ограниченной ситуации остается только применить явное приведение типа. Чтобы не замусоривать код явными приведенями можно, если вам не претит такая практика, спрятать его в макро #define sorting(p) sorting((const char **) (p))

воскресенье, 8 декабря 2019 г.

Разница между const и constexpr

#cpp #cpp11 #const


В чём разница между const int x и constexpr int x? Что из этого стоит использовать? 
    


Ответы

Ответ 1



Самый простой пример. Данная программа компилируется #include struct A { constexpr static double x = 10.0; }; int main() { A a; return 0; } А данная программа нет. #include struct A { const static double x = 10.0; }; int main() { A a; return 0; } Существенное значение также имеет место, когда этот спецификатор, constexpr, используется для функций. Как вы знаете, только функции-члены класса могут иметь квалификатор const, который имеет отношение к объекту, для которого вызывается данная функция-член класса. Обычные функции не могут быть константными. Спецификатор constexpr введен для того, чтобы заставить компилятор на этапе кмпиляции создавать объекты и использовать их как константы времени компиляции. Например, известно, что стандарт C++ для задания размерности массива требует константное выражение. Используя спецификатор constexpr вы можете задавать размер массива, используя некоторые функции. Например, #include struct A { constexpr A( bool b ) : n( b ? 5 : 10 ) {} size_t n; }; int main() { int a[A( true ).n]; int b[A( false ).n]; int i = 0; for ( int &x : a ) x = i++; i = 0; for ( int &x : b ) x = i++; for ( int x : a ) std::cout << x << ' '; std::cout << std::endl; for ( int x : b ) std::cout << x << ' '; std::cout << std::endl; return 0; } Вывод программы на консоль 0 1 2 3 4 0 1 2 3 4 5 6 7 8 9 Использование constexpr позволяет заниматься метапрограммированием на этапе компиляции, как альтернативная возможность для шаблонного метапрограммирования.

Ответ 2



const int x - переменная x не должна меняться в процессе работы программы, а constexpr int x - оно еще и должна получить свое значение во время компиляции... Например, int n; cin >> n; const int x = n*n; Отработает, x получит свое значение, которое нельзя будет менять - но получит во время работы программы. Если написать constexpr - не скомпилируется, ибо во время компиляции x не известно. Соответственно этому - используйте то, что боее подходит для ваших целей. Где можно - лучше constexpr, где нет - просто const.

суббота, 7 декабря 2019 г.

Всплывают ли переменные, объявленные с помощью let и const в ES6?

#javascript #ecmascript_6 #const #let #hoisting


Проверяя новшества ES6, я обратил внимание, что переменные объявленные с var всплывают
как и ожидалось...

console.log(typeof name); // undefined
var name = "John";


...в то время как, переменные объявленные с помощью let или const похоже имеют с
подъемом некоторые проблемы:

console.log(typeof name); // ReferenceError
let name = "John";


и

console.log(typeof name); // ReferenceError
const name = "John";


Означает ли это, что переменные объявленные с помощью let или const не всплывают?
Что происходит здесь на самом деле? Есть ли разница между let и const в этом случае?



Перевод вопроса: Are variables declared with let or const not hoisted in ES6?

    


Ответы

Ответ 1



tl; dr; цитата из секции 13.3.1 Let and Const Declarations The variables are created when their containing Lexical Environment is instantiated but may not be accessed in any way until the variable's LexicalBinding is evaluated. Переменные создаются когда инстанциируется содержащий их Lexical Environment, но остаются недоступными никоим образом до вычисления их LexicalBinding. Так что, ответ на твой вопрос: да, let и const всплывают, но ты не можешь получить доступ к ним, до выполнения фактического определения в run-time. Как сказано выше, эти переменные не могут быть доступны, до их объявления. Однако, все немного сложнее. Означает ли это, что переменные объявленные с помощью let или const не всплывают? Что происходит здесь на самом деле? В JavaScript все определения (var, let, const, function, function*, class) всплывают. Это значит, что если имя определено в скопе, в этом скопе идентификатор всегда будет указывать на конкретную переменную: x = "global"; // функциональный скоп: (function() { x; // не "global" var/let/… x; }()); // блочный скоп (не для `var`): { x; // не "global" let/const/… x; } Это верно и для функционального, и для блочного скопов1. Различие между определениями var/function/function* и let/const/class в их инициализации. Первые инициализируются значением undefined или функцией (генератором) прямо когда создается связывание в начале скопа. Однако, лексически объявленные переменные остаются неинициализированными. Это значит, что при попытке доступа к ним будет брошено исключение ReferenceError. Инициализируются они. только в момент выполнения выражений let/const/class, все перед этим (выше) называется временная мертвая зона (temporal dead zone). x = y = "global"; (function() { x; // undefined y; // Reference error: y is not defined var x = "local"; let y = "local"; }()); Обратите внимание, что выражение let y; инициализирует переменную значением undefined, аналогично выражению let y = undefined;. Временная мертвая зона, это не синтаксическое место, а, скорее, время между созданием переменной (скопа) и инициализацией. Так, не будет ошибкой обращение к переменной в коде выше определения, пока этот код не будет выполнен (например тело функции или просто недостижимый код), но будет выкинуто исключение пи попытке доступа к переменной до ее инициализации, даже если код доступа расположен ниже определения (например, в всплывшем определении функции, которая была вызвана слишком рано). Есть ли разница между let и const в этом случае? Нет, они работают абсолютно одинаково, если рассматривать со стороны всплытия. Единственное отличие их в том, что constанты должны и могут быть присвоены только в части инициализатора определения (const one = 1;, вариант const one; с последующим присвоением значения one = 2 недопустим). 1: естественно, определение var работает только на уровне функции Переводы ответов @thefourtheye и @Bergi