Почему у scala нет C ++ - как const-семантики? - PullRequest
20 голосов
/ 05 октября 2010

В С ++.Я могу объявить большинство вещей как const, например:
Переменные: const int i=5;
Scala имеет val i=5, однако это только предотвратит переназначение, не изменяя объект, как показано в следующем примере:
C ++:

const int i[]={1,2,3,4};
i[2]=5; //error
Scala:
<code>val a=Array(1,2,3,4)
a(2)=5 //a is now Array(1, 2, 5, 4)

С функциями-членами становится еще хуже:
C ++:

<code>class Foo {
int i;
int iPlusFive() <b>const</b> {return i+5;}
int incrementI(){ return ++i; }
}
Я могу быть уверен, что вызов iPlusFive не изменит объекти что я не буду случайно вызывать incrementI для const-объекта.

Когда дело доходит до коллекций, C ++ продолжает свою константно-правильную серию с коллекциями const: просто объявите свой вектор как const, и вы не сможете его изменить,Присвойте non-const vector<Int> const vector<Int>, и компилятор не будет ничего копировать и помешает вам что-либо изменить в коллекции const.

Scala имеет scala.collection.mutable.whothing и scala.collection..immutable.w чем бы то ни было, вы не можете просто преобразовать изменяемые коллекции в неизменяемые коллекции, более того, вы все равно можете изменять собранные объекты с помощью их неконстантных функций-членов.

Почему scala, которая имеет иноедействительно отличная система типов, не имеет ничего похожего на const-ключевое слово C ++?

Редактировать: Маргус предложил использовать import scala.collection.mutable.Мое решение состояло в том, чтобы использовать

import scala.collection.mutable.HashMap
import scala.collection.immutable.{HashMap => ConstHashMap}
Это сделает изменяемый HashMap доступным как HashMap и неизменный als ConstHashMap, однако мне все еще нравится подход C ++ лучше.

Ответы [ 4 ]

10 голосов
/ 05 октября 2010

Что мне не нравится в константной логике C ++, так это то, что она касается ссылки, а не объекта, на который ссылаются.Если у меня есть «const T *», нет никакой гарантии, что кто-то, имеющий неконстантный указатель, не изменит состояние объекта.Таким образом, это никоим образом не помогает избежать состояния гонки в многопоточных системах и не помогает в реализации постоянных контейнеров.

На мой взгляд, очень полезно иметь представление о неизменяемых классах и отсутствиинеизменяемые контейнеры в стандартной библиотеке - ошибка на любом языке.Так как они должны демонстрировать наблюдаемую неизменность, но, вероятно, должны будут иметь возможность изменять внутреннее / невидимое состояние по соображениям эффективности, я думаю, что const-синтаксис не поможет.

В Scala есть неизменяемые классы, которые нам нужно либо использовать напрямуюили основывать другие неизменные классы на.Это чрезвычайно ценно.Дополнительный синтаксис может быть хорошим дополнением, но я могу жить без него.

6 голосов
/ 05 октября 2010

Потому что C ++ const не так хорош в сложных системах.

Я могу быть уверен, что вызов iPlusFive не изменит объект и что я не буду случайно вызывать incrementI для объекта const.

Нет, вы можетет, потому что реализация (которая может быть в библиотеке где-то вне поля зрения) может отбросить константу.Без const другие языки должны обеспечивать неизменность более безопасными способами (см., Например, Collections.unmodifiableList () в ответе @ Margus).

Const - это просто документация, которую читает компилятор.Документация, как правило, полезна, но иногда вводит в заблуждение.

Когда дело доходит до коллекций, C ++ продолжает свою корректную последовательность с коллекциями const: просто объявите свой вектор как const, и вы не сможете его изменить.

Агрегация - это то, где const часто ломается для меня.Я часто хочу объявить, например, что метод не изменит вектор, но может изменить его член (или вернуть неконстантную ссылку на член).Я должен сделать все это постоянным или неконстантным или придумать новые вариации типа для каждой комбинации.

«изменяемый» компенсирует некоторые проблемы агрегации, но вносит больше сложности и неправильного использования.

5 голосов
/ 05 октября 2010

IMO, Scala просто дает больше гибкости, не смешивая неизменность ссылки с [возможной] изменчивостью структуры, стоящей за ней, давая вам возможность принимать проектное решение WRT с проблемой, с которой вы сталкиваетесь.

3 голосов
/ 05 октября 2010

Весь код Scala переведен на код Java, поэтому я сделал примеры на Java.

Вот как это сделать в Java:

    Integer x[] = new Integer[]{1,2,3,4}; 
    final List<Integer> CONST = Collections.unmodifiableList(Arrays.asList(x));

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

Источник: ссылка

Массив с неизменяемым содержимым?

Java не предоставляет понятие массив const: массив, который можно поменять местами на новый массив (в C ++ термины «указатель может быть изменен»), но чьи элементы не могут быть изменены. Однако, если вам это нужно функциональность, решение как правило, очень похоже на предоставление доступ только для чтения к любому другому объекту как обсуждается ниже. Итак, пара Возможности:

  • вы можете создать неизменяемый список, передав список в Collections.unmodifiableList () (хотя в этом случае переменная будет объявлен типа List, а не типа который пометил его как «неизменяемый» - как обсуждается ниже, любая попытка изменить это будет замечено во время выполнения);
  • вы можете создать объект-оболочку вокруг частного массива и предоставить публичные методы читать, но не писать его элементы;
  • Вы можете использовать IntBuffer только для чтения (или FloatBuffer и т. Д.): ...

Источник: Java-эквиваленты - const с точки зрения c ++.

Итак, эквивалент для Scala:

    val A = Set(1, 2, 3, 4)

    val A = List(1, 2, 3, 4)

Это должно перевести на:

    scala.collection.immutable.List[java.lang.Integer] A = List(1, 2, 3, 4)

Это может объяснить мой ответ на комментарий IttayD, почему java 6 отличается от компилятора c ++:

Reified Generics

В настоящее время дженерики реализованы используя стирание, что означает, что информация общего типа не доступны во время выполнения, что делает некоторые код, который сложно написать. Дженерики были реализованы таким образом, чтобы поддержать обратная совместимость со старыми неуниверсальный код Reified дженерики сделает общий тип информация, доступная во время выполнения, который сломал бы наследие, не являющееся родовым код. Тем не менее, Нил Gafter имеет предлагаемые виды изготовления если указано, чтобы не сломать обратная совместимость.

Источник: ссылка

Глупо даже упоминать, но в соглашениях об именах констант Java используется заглавная буква для переменной. Другие, читающие ваш код, сразу узнают, что идентификатор является фиксированным постоянным значением, которое нельзя изменить.

Источник: ссылка

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

Полезным соглашением, если вы хотите использовать как изменяемые, так и неизменяемые версии коллекций, является импорт только пакета collection.mutable.

import scala.collection.mutable

Источник: API Scala Collection

Не уверен, что вы подразумеваете под конвертированием, но вы, вероятно, можете сделать:

val a = scala.collection.mutable.List[Int](1, 2, 3)
val A = scala.collection.immutable.List[Int](a.toArray())
...