2013-06-24 15 views
30

A partire da 2.10, -Xlint si lamenta delle classi definite all'interno degli oggetti del pacchetto. Ma perché? Definire una classe all'interno di un oggetto pacchetto dovrebbe essere esattamente equivalente alla definizione delle classi all'interno di un pacchetto separato con lo stesso nome, tranne che molto più conveniente.Perché le classi all'interno degli oggetti del pacchetto Scala sono dispreitate?

A mio parere, uno dei gravi difetti di progettazione di Scala è l'impossibilità di mettere qualcosa di diverso da un'entità di classe (ad esempio dichiarazioni di variabili, definizioni di funzioni) al livello più alto di un file. Invece, sei costretto a metterli in un "oggetto pacchetto" separato (spesso in package.scala), separati dal resto del codice a cui appartengono e violando una regola di programmazione di base che è che il codice concettualmente correlato dovrebbe essere fisicamente correlato pure. Non vedo alcun motivo per cui Scala non possa concettualmente concedere nulla di livello superiore che consenta a livelli inferiori, e qualsiasi cosa non di classe venga automaticamente inserita nell'oggetto pacchetto, in modo che gli utenti non debbano mai preoccuparsi di ciò.

Per esempio, nel mio caso ho un pacchetto util, e sotto di esso ho un certo numero di pacchetti secondari (util.io, util.text, util.time, util.os, util.math, util.distances, etc.) che di gruppo collezioni eterogenee di funzioni, classi e a volte variabili che sono semanticamente correlate. Attualmente memorizzo tutte le varie funzioni, classi, ecc. In un package object seduto in un file chiamato io.scala o text.scala o qualsiasi altra cosa, nella directory util. Questo funziona benissimo ed è molto comodo a causa del modo in cui funzioni e classi possono essere mescolate, ad es. Posso fare qualcosa di simile:

package object math { 
    // Coordinates on a sphere 

    case class SphereCoord(lat: Double, long: Double) { ... } 

    // great-circle distance between two points 
    def spheredist(a: SphereCoord, b: SphereCoord) = ... 

    // Area of rectangle running along latitude/longitude lines 
    def rectArea(topleft: SphereCoord, botright: SphereCoord) = ... 

    // ... 
    // ... 

    // Exact-decimal functions 
    class DecimalInexactError extends Exception 

    // Format floating point value in decimal, error if can't do exactly 
    formatDecimalExactly(val num: Double) = ... 

    // ... 
    // ... 
} 

Senza questo, avrei dovuto dividere il codice fino sconvenientemente in base al divertimento vs classe piuttosto che per la semantica. L'alternativa, suppongo, è di metterli in un oggetto normale - tipo di sconfiggere lo scopo di avere oggetti pacchetto in primo luogo.

risposta

26

Ma perché? La definizione di una classe all'interno di un oggetto pacchetto dovrebbe essere esattamente equivalente alla definizione delle classi all'interno di un pacchetto separato con lo stesso nome,

Precisamente. La semantica è (attualmente) la stessa, quindi se si preferisce definire una classe all'interno di un oggetto pacchetto, ci dovrebbe essere una buona ragione. Ma la realtà è che c'è almeno un buon motivo no (continua a leggere).

tranne molto più conveniente

Come è che più conveniente? Se si sta facendo questo:

package object mypkg { 
    class MyClass 
} 

si può solo così effettuare le seguenti operazioni:

package mypkg { 
    class MyClass 
} 

Potrai anche salvare un paio di caratteri nel processo :)

Ora, un buona e concreta ragione per non esagerare con gli oggetti del pacchetto è che mentre i pacchetti sono aperto, gli oggetti del pacchetto sono non. Uno scenario comune potrebbe essere l'invio del codice tra più progetti, con ogni progetto che definisce le classi nello stesso pacchetto.Nessun problema qui. D'altra parte, un oggetto pacchetto è (come qualsiasi oggetto) chiuso (come specifica lo specifica "Ci può essere solo un oggetto pacchetto per pacchetto"). In altre parole, potrai definire un oggetto pacchetto in uno dei tuoi progetti. Se si tenta di definire un oggetto pacchetto per lo stesso pacchetto in due progetti distinti, accadranno cose brutte, in quanto si otterranno due versioni distinte della stessa classe JVM (nel nostro caso si finirebbe con due " mypkg.class "). A seconda dei casi si potrebbe finire con il compilatore lamentandosi del fatto che non è possibile trovare qualcosa che è stato definito nella prima versione dell'oggetto pacchetto, o ottenere un "errore di riferimento simbolico", o potenzialmente anche un errore di runtime. Questa è una limitazione generale degli oggetti del pacchetto, quindi devi esserne consapevole. Nel caso di definizione di classi all'interno di un oggetto pacchetto, la soluzione è semplice: non farlo (dato che non otterrai nulla di sostanziale rispetto alla semplice definizione della classe come livello principale). Per tipo aliase, vals e vars, non abbiamo un tale luxuary, quindi in questo caso si tratta di valutare se la convenienza sintattica (rispetto a definirli in un oggetto) valga la pena, e quindi fare attenzione a non per definire oggetti del pacchetto duplicati.

+5

hai frainteso il mio reclamo. Se ho un pacchetto di utilità con entrambe le classi e funzioni, allora (a) Devo segregare le classi e le funzioni, il primo in un pacchetto, il secondo in un oggetto pacchetto con lo stesso nome, o li metto insieme in un oggetto del pacchetto, che è "deprecato". Il problema con la separazione è che rende impossibile mantenere insieme pacchetti e funzioni correlate. –

+0

Ho riscritto la domanda per chiarire il problema. –

+0

Sebbene gli oggetti del pacchetto non siano aperti, il loro pacchetto corrispondente lo è ancora. Io uso molto gli oggetti del pacchetto (sono moduli mimmici in altri linguaggi di programmazione) e devo ancora incontrare tutti i problemi che descrivi. –

1

Non ho trovato una buona risposta al motivo per cui questa operazione semanticamente equivalente genererebbe un avviso di sfilacciamento. Pensa che questo sia un bug di lanugine. L'unica cosa che ho trovato che non deve essere essere inserito all'interno di un oggetto pacchetto (vs all'interno di un pacchetto normale) è un oggetto che implementa main (o extends App).

Si noti che -Xlint si lamenta anche delle classi implicite dichiarate all'interno degli oggetti del pacchetto, anche se non possono essere dichiarate nell'ambito del pacchetto. (Vedere http://docs.scala-lang.org/overviews/core/implicit-classes.html per le regole sulle classi implicite.)

-1

Ho individuato un trucco che consente tutti i vantaggi degli oggetti del pacchetto senza i reclami relativi alla deprecazione. Al posto di

package object foo { 
    ... 
} 

si può fare

protected class FooPackage { 
    ... 
} 

package object foo extends FooPackage { } 

lavori lo stesso, ma nessuna denuncia. Chiaro segno che la denuncia stessa è falsa.

+4

No, segno chiaro di nient'altro che il fatto che il compilatore ha dei limiti e non può catturare tutto. Questo non dice nulla sulla validità dell'avvertimento in primo luogo. Un avvertimento è proprio questo: il compilatore che ti dice ** può ** correre nei problemi quando fa qualcosa (e qui sei sicuro di sì, hai letto correttamente la mia risposta?). –

Problemi correlati