10
votes

Pourquoi le scala for-boucle (et les internes) Numericrange est-il limité à la taille INT et à élaborer la fonctionnalité?

Qu'est-ce qui est derrière la restriction de taille Numericrange Int sur la compréhension de Scala for-boucle? Est-il possible (sans trop de mal à la tête) pour prolonger "pour / SQS", numericrange pour utiliser de longues (ou quelque chose de plus grand que INT.MAXValue)?

scala> code> b> pour (i: long p>

java.lang.IllegalArgumentException: 0 to 10000000000L by 1: "seqs cannot contain more than Int.MaxValue elements."
    at scala.collection.immutable.NumericRange$.count(NumericRange.scala:227)
    at scala.collection.immutable.NumericRange.numRangeElements(NumericRange.scala:53)
    at scala.collection.immutable.NumericRange.length(NumericRange.scala:55)
    at scala.collection.immutable.NumericRange.foreach(NumericRange.scala:73)
    at .<init>(<console>:19)
    at .<clinit>(<console>)
    at .<init>(<console>:11)
    at .<clinit>(<console>)
    at $print(<console>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:704)
    at scala.tools.nsc.interpreter.IMain$Request$$anonfun$14.apply(IMain.scala:920)
    at scala.tools.nsc.interpreter.Line$$anonfun$1.apply$mcV$sp(Line.scala:43)
    at scala.tools.nsc.io.package$$anon$2.run(package.scala:25)
    at java.lang.Thread.run(Thread.java:680)


0 commentaires

4 Réponses :


9
votes

in Scala Il n'y a pas de boucle, mais une compréhension. Cela fonctionne différent d'une boucle. En fait, votre compréhension est traduite en:

var i = 0L
while(i < 10000000000) {
  // do stuff
  i+=1
}


9 commentaires

Merci pour le repli, je suis tout à fait au courant du sucre de la syntaxe de compréhension. Mais le point était "pourquoi" SEQ est restreint (comme indiqué dans la question) et si SEQ est très extensible?


Donc, ce que vous signifiez fondamentalement, c'est que la compréhension n'est pas suffisamment mature pour être utilisée dans la production? Est-ce une faille de conception de bibliothèque ou une question de langage?


Non, cela signifie seulement que pour la construction nécessite une séquence d'éléments et la construction d'une telle construction ne peut pas être effectuée avec la taille que vous attendez, en raison de la limitation de la mémoire (voir la dernière version de ma réponse).


Non, les compréhensions sont tout simplement bien pour les sections de votre application à la non-performance. Il est plus lent qu'une boucle, mais aussi plus puissante. Si vous travaillez avec MONADS FOR-COMPRENSIONS, mais pas pour itération sur de grandes collections.


@Nicolas pour ne nécessite pas de séquence, mais une monade.


Ni un SEQ, ni une monade, comme Monad n'est pas un trait à Scala. En fait, je pense que cela nécessite quelque chose qui peut être transféré dans un itérateur (à vérifier)


@Drexin: Cette citation va directement dans nos lignes de guide de conception. Merci! IMO - Cela devrait également être adressé dans une sorte de "Guide de conception Scala" officiel "


@Nicolas Vous avez raison, Monad n'est pas un type de scala, mais un rendement pour (...) prend tout ce qui a mappe et plattmap Mise en œuvre, un simple pour sans le rendement prend n'importe quoi, qui a pour objectif de mettre en œuvre. Vous voudrez peut-être lire cet article sur Monads à Scala: James-iry.Blogspot.de/2007/09/monads-are-Elesphanpes-part--.ht ml


Hum oui, ça marche, je suis à peu près sûr que cela n'a pas été mis en œuvre grâce aux types de structure.



8
votes

réponse courte - il semble être une "fonctionnalité" - au moins, il fonctionne comme conçu.

Comme @Drexin a souligné, la mise en œuvre de "to" est limitée à avoir une plage int. Cependant ...

Le problème est que Numericrange [t] .Count (), .numrangselements et .length () renvoie un INT - peu importe ce que T est. Dans ce cas, c'est un Numericrange [long], où il semble un peu faux d'avoir compté () limité à 31 bits, IMHO.
Cependant ...

Parcourir les problèmes de JIRA, cela semble fonctionner comme conçu. Voir, E.G., SI-4370 . Mais juste pour être sûr que cela a été pensé à cette perspective, j'ai entré SI-5619 .


18 commentaires

Il n'est pas limité à une gamme, c'est-à-dire ce que vous créez. Vous pouvez transmettre n'importe quelle monade à une compréhension.


@Ed Staub - C'est exactement mon point c'est-à-dire pourquoi. Pourquoi le nombre de gammes () limité à int! IMHO c'est assez étrange mais la grande question reste: est-ce un bug ou une fonctionnalité ;-)


@Drexin: une idée de la raison pour laquelle la plage compte par défaut sur INT?


Peut-être à cause de la compatibilité avec la JVM 32bit. Mais c'est juste une supposition.


@IDev Votre mise à jour n'est également pas entièrement vraie, car vous pouvez avoir une gamme de longs, tant que vous n'avez pas plus d'éléments d'int.maxValue. Par exemple, 0L à 100000000000L par 1000000 fonctionne juste bien.


@Drexin - Je fais référence à l'erreur spécifique iodev dans. Il est possible d'utiliser une monade avec une boucle avec plus de 2 gigaitères - c'est juste ce particulier (numericrange) qui a la limitation - ne pas dire qu'il n'y a pas d'autres personnes avec la même limite.


Toutes les idées / réflexions de GRENRAL: La limitation de l'int.maxvalue est-elle si numericrange une "défaute" de conception doit être améliorée?


C'est définitivement une faille. Puisque vous pouvez construire une telle gamme, mais il échoue dès que vous appelez une méthode qui nécessite de vérifier sa longueur.


@Nicolas, ce n'est certainement pas une faille. 0L à 100000000000L n'est pas valide, mais 0L à 100000000000L par 1000000 est valide, aucune exception ne peut être lancée dans le premier cas ou le second cas ne serait pas possible. La limite int est liée à la performance, Taille , Appliquer sur SEQ et les propres limitations de Java, en particulier la taille de tableau .


@Daniel Une exection peut être lancée si nous n'agissons pas paresseux eval comptent . Sinon, nous pouvons aussi bien essayer de limiter l'utilisation de la limite de de longueur (surtout dans le cas de Teach)


@Nicolas c'est le point. Une exception sera lancée si Nombre n'est pas évalué paresseusement, mais ce qui ne va pas pour 0L à 100000000000L par 1000000 . Et tandis que longueur peut se comporter un peu différemment (et fait, pour les collections infinies), appliquer ne peut pas. Bien que pour être sûr, on pourrait théoriquement dépasser int.maxvalue avec un flux infini , donc il y a certainement une contradiction là-bas.


@ DanielC.Sobral Non, ce n'est pas le cas: (0L ​​à 100000000000L par 1000000) .Length fonctionne comme un charme et appelle numericrange.count .


En fait, il semble vraiment que l'échec de l'initialisation de numericrange.count effectue exactement ce que nous attendons. Mais à coup sûr, cela ne résout pas le problème de consistance que nous disposons avec un flux infini .


@Nicolas bien, allez-y et écrivez le patch.


@ DanielC.Sobral Pensez-vous que la pénalité de performance d'évaluation de la longueur pendant l'initialisation est acceptable? C'est le dernier doute que j'en ai à ce sujet.


@Nicolas - J'ai bien peur de ne pas comprendre ce que le correctif proposé est. Mais la pénalité de performance: je ne m'inquiéterais pas à ce sujet, car le nombre () / longueur () est utilisé de manière omniprésente dans la classe. Equals (), Tostring, Foreach () ... Il est difficile d'imaginer que quelqu'un voulant utiliser un objet si fragile, il suffit d'attendre que la mauvaise méthode soit appelée à décomposer à l'hystérie ;-).


@Nicolas la pénalité de performance d'un paresseux val loin dépasse la pénalité de performance de précompouver la taille, de sorte que ce serait plus rapide de ne pas en faire un Lazy Val .


J'ai détaillé quel est le problème selon moi et certaines alternatives là-bas: Problèmes.scala-Lang. Org / Browse / SI-5622



2
votes

Les méthodes taille et longueur renvoient un int , il ne serait donc pas possible de retourner une valeur supérieure à Int.maxvalue . Sur SEQ , aussi, la méthode appliquer prend un int , souffrant du même problème. Les collections Scala, comme les collections Java sont donc limitées à int.maxvalue éléments.


2 commentaires

Donc, pour faire face aux collections SEQ plus grandes que Int.Maxsize, nous avons besoin d'un BigSeq? ;-)


@Iodev Il y a une question pratique d'utilité des collections qui grandes. Je pense que le vrai problème est que, peut-être, les gammes ne devraient pas être des collections, ont simplement des conversions dans collections.



2
votes

Vous ne pouvez pas compter les éléments aussi longtemps que leur compte ne correspond pas à int code>, car longueur code> est déclaré pour retourner int code>, mais ici est le raccourci: vous pouvez créer itérateurs em> avec toute taille réelle em>, tant que vous n'essayez pas de les compter.

scala> def longRange(first: Long, last: Long) = new Iterator[Long] {
    private var i = first
    def hasNext = i < last
    def next = {val r = i; i += 1; r}
}
longRange: (from: Long, to: Long)java.lang.Object with Iterator[Long]

scala> val lol = longRange(0, Long.MaxValue) map (x => x * x)
lol: Iterator[Long] = non-empty iterator

scala> lol drop 5 take 5 foreach println
25
36
49
64
81


2 commentaires

Fonctionne bien sur Scala 2.9, Scala 2.10 crie les points suivants: Scala> Def Longrange (à partir de: Long, à: Long) = Nouveau Itérateur [LONG] {| Var i: long = de | def hasnext = i <à | DEF NEXTE = {VAL R = I; i + = 1; r} | } : 10: Erreur: méthode surchargée Valeur (x: int) booléen (x: char) booléen (x: short ) Booléen (x: octet) booléen ne peut pas être appliqué à (scala.collection.immutable.indexedseq [long]) def hasnext = i <à ^


On dirait que Scala Compiler est confondu par à mot, car il existe une méthode avec ce nom. Peut-être que quelque chose s'est mal passé dans leur définition de syntaxe. BTW, j'ai commencé à penser que cette partie de Scala Syntaxe (permet de permettre des appels de méthode "style space" au lieu de "style de points" pour tous les noms, non seulement "symboles spéciaux" comme + , + + , :: , etc.) est diabolique. Ici y a l'exemple de travail: ideone.com/z5989q , et si nous renommerons fin à à , il ne compile pas: ideone.com/6fadfe . Peut-être que c'est un sujet juridique de signaler un bogue.