2014-11-20 1 views
1

내 스칼라 코드에 버그가 있습니다. 변수에 여러 가지 연산을 수행하여 중간 변수를 많이 만듭니다.어떤 언어로도 범위에서 변수를 제거 할 수 있습니까?

class SomeClass(name: String) { 

    def doSomeThings() { 
    val canonicalizedName = canonicalizeName(name) 
    val boozbangledName = boozbangle(canonicalizedName) 
    val plobberedName = plobber(boozbangledName) 
    val flemmedName = flem(boozbangledName) // bug! should have been flem(plobberedName) 
    // (more code) 
    doAThing(flemmedName) // correct! 
    doAnotherThing(name)  // bug! should have been doAnotherThing(flemmedName) 
    } 
} 

모든 프로그래밍 언어에서 이러한 종류의 버그를 예방할 수있는 방법이 있습니까? 범위에서 "사용되지 않는"변수를 제거 하시겠습니까? 내가 처음 버그를 방지하기 위해 var를 사용할 수 있지만 여전히 방지하지 않는 두 번째 :

class SomeClass(name: String) { 

    def doSomeThings() { 
    var fixedName = name 
    fixedName = canonicalizeName(fixedName) 
    fixedName = boozbangle(fixedName) 
    fixedName = plobber(fixedName) 
    fixedName = flem(fixedName) 
    // (more code) 
    doAThing(fixedName) // good! 
    doAnotherThing(name)  // bug! should have been doAnotherThing(flemmedName) 
    } 
} 

}

+0

일부 사람들은 첫 번째 방법이 실제로 더 읽기 쉽다고 주장합니다. 그것은 메서드를 호출 할 때 순서가 중요하다는 것을 명확하게 나타냅니다. – mdnghtblue

+0

이 중간의 모든 작업을 수행하고 flemmedName을 반환하는 별도의 메서드에이 처음 네 줄을 넣는 것은 어떻습니까? doSomeThings()에는 하나의 변수 만 있습니다. 문제 해결됨. – makingthematrix

답변

2

의 나쁜 이름, 복제 또는 위반을 지적 할 수있는 변수 이름과 혼동 가져 오는 동안 demeter의 법칙에 따르면 실제로 매크로를 사용하여 Scala에서 "val-deprecation"기능을 구현할 수 있습니다.

방금 ​​매크로를 작성하는 방법을 배우기 시작 했으므로 만족스러운 구현을 제공 할 수는 없지만 - 염두에두고있는 것을 설명하기 위해 - 나는 가장 간단한 구현을 생각해 냈습니다. 발의 이름 표현에 포함되어 있습니다. 또한 매크로는 Unit 식만 반환하며 제네릭 형식 매개 변수를 사용하여 일반화 할 수 있습니다. 그러나 더 나은보고 더 강력한 구현을 내놓을 수 있어야합니다.

매크로는 다른 코드보다 먼저 컴파일해야하므로 별도의 프로젝트에서 매크로를 구현해야합니다. 로 볼 수

순진 매크로 구현은 다음과 같습니다 action가 제공 val의 식별자를 포함하는 경우, 컴파일시에 오류를 생성 할

package mymacros 

object Macros { 
    import scala.language.experimental.macros 

    def deprecatedValue_impl(c: scala.reflect.macros.blackbox.Context)(value: c.Expr[Any])(action: c.Tree): c.Tree = { 
    import c.universe._ 
    val valueName = show(value.tree) 
    if(show(action).contains(valueName)) { 
     throw DeprecatedValueUsed(valueName) 
    } 
    action 
    } 

    def deprecatedValue(value: Any)(action: => Unit): Unit = macro deprecatedValue_impl 

} 

case class DeprecatedValueUsed(valueName: String) extends Error // Add a nice error message here 

. , SI-5778 따른 Tree 대신 Expr를 사용하여 통화 별 파라미터 이름을 허용

object DeprecateNames { 
    import mymacros.Macros._ 

    def main(args: Array[String]): Unit = { 
    val flobberwobber = "hello" 
    val flabberwabber = "world" 
    deprecatedValue(flobberwobber){ 
     // println(flobberwobber) doesn't compile 
     println(flabberwabber) 
     // println(flobberwobber + flabberwabber) doesn't compile 
     println("hello" + "world") 
     // println("flobberwobber") doesn't compile 
    } 
    } 
} 

참고 스칼라 2.11 이후에만 가능하다.

2

당신이 정말로하고 싶은 것은 그러한 모든 기능을 구성하는 것 같습니다. 이는 중간 값이 "누출되지"않는 일련의 연산에 대한 개념을 포착합니다. 모두 Function1 인스턴스 (_ 연산자를 사용하여 메서드를 함수로 강제 변환 할 수 있음)라고 가정하면이 연산자를 구성 할 수있는 andThen 연산자가 있습니다. 그래서 당신은 같은 것을 할 수있다 : 즉

class SomeClass(name: String) { 
    def doSomeThings() { 
    val processChain = Seq(canonicalizeName, boozbangle, plobber, flem, doAThing, doAnotherThing) 
    processChain.reduce(_ andThen _)(name) 
    } 
} 

을,이 단항 함수는 운영자로 구성 (andThen)과 더불어, semigroup이다. 사실, 그들은 실제로 이고, ID는입니다. 그러나이 속성은 미리 정의 된 함수 목록이므로 여기서는 사용하지 않습니다. fold 변수 목록을 원하면 identity을 기본 사례로 사용하면 해당 옵션이 적용됩니다.

나에게 일어난 다른 일은 원하는 안전을 달성하기 위해 유형 시스템을 사용할 수 있다는 것입니다.중간 값을 모든 함수에 대해 "부적합"이라고 태그 지정하려는 경우 하나의 인수 인 case class을 적용하여 sigils과 같은 종류의 동작을 수행 한 다음 함수에 적절한 입력을 제공하면 출력 형식을 사용하면 중간 변수를 유지할 수 있지만 형식이 허용하는 것보다 다른 방법으로는 사용할 수 없습니다.

그리고 어떤 언어로 변수를 제거 할 수 있는지에 대한 질문에 대답하기 위해 파이썬에는 del keyword이 있습니다.

2

이미 많은 좋은 제안이 있습니다. 이 문제에 도움이되는 또 다른 기술은 다음과 같습니다.

class SomeClass(name: String) { 
    def doSomeThings() { 
    val flemmedName = { 
     val plobberedName = { 
     val canonicalizedName = canonicalizeName(name) 
     val boozbangledName = boozbangle(canonicalizedName) 
     plobber(boozbangledName) 
     } 
     flem(boozbangledName) // compilation error 
    } 
    // (more code) 
    doAThing(flemmedName) // correct! 
    doAnotherThing(name)  // sorry, can't help with this one 
    } 
} 
관련 문제